ソースを参照

Add ability to edit RcGcDb webhook

Markus-Rost 4 年 前
コミット
9e5dbad7e6
8 ファイル変更218 行追加60 行削除
  1. 12 5
      dashboard/i18n/en.json
  2. 7 2
      dashboard/index.js
  3. 91 12
      dashboard/rcscript.js
  4. 7 0
      dashboard/src/index.css
  5. 57 3
      dashboard/src/index.js
  6. 4 4
      dashboard/util.js
  7. 5 1
      i18n/en.json
  8. 35 33
      main.js

+ 12 - 5
dashboard/i18n/en.json

@@ -30,6 +30,10 @@
         "welcome": "<h2>Welcome to the Wiki-Bot Dashboard.</h2>\n<p>Wiki-Bot is a Discord bot made to bring Discord servers and MediaWiki wikis together. It helps with linking wiki pages, verifying wiki users, informing about latest changes on the wiki and more. <a href=\"https://wiki.wikibot.de/wiki/Wiki-Bot_Wiki\" target=\"_blank\">[More information]</a></p>\n<p>Here you can change different bot settings for servers you have Manage Server permission on. To begin, you will have to authenticate your Discord account which you can do with this button:</p>"
     },
     "indexjs": {
+        "avatar": {
+            "content_type": "The provided link has the content type $1, but only the following content types are allowed:",
+            "invalid_url": "The URL couldn't be resolved to a valid image file."
+        },
         "invalid": {
             "note_http": "The provided website doesn't have a valid TLS/SSL certificate! For security reasons only wikis using HTTPS are supported.",
             "note_private": "The provided wiki is private!",
@@ -76,11 +80,6 @@
             "text": "Either you or Wiki-Bot are missing the $1 permission for this function.",
             "title": "Missing permission!"
         },
-        "movefail": {
-            "note": "The webhook channel could not be changed!",
-            "text": "The settings have only been partially updated.",
-            "title": "Settings partially saved!"
-        },
         "mwversion": {
             "text": "Requires at least MediaWiki 1.30, found $1 on $2.",
             "title": "Outdated MediaWiki version!"
@@ -134,6 +133,11 @@
             "text": "Please login before you can change any settings.",
             "title": "Not logged in!"
         },
+        "webhookfail": {
+            "note": "The Discord webhook could not be changed!",
+            "text": "The settings have only been partially updated.",
+            "title": "Settings partially saved!"
+        },
         "wikiblocked": {
             "note": "Reason:",
             "text": "$1 has been blocked from being added as a recent changes webhook.",
@@ -144,6 +148,8 @@
         "desc": "These are the recent changes webhooks for $1:",
         "explanation": "<h2>Recent Changes Webhook</h2>\n<p>Wiki-Bot is able to run a recent changes webhook based on <a href=\"https://gitlab.com/piotrex43/RcGcDw\" target=\"_blank\">RcGcDw</a>. The recent changes can be displayed in compact text messages with inline links or embed messages with edit tags and category changes.</p>\n<p>Requirements to add a recent changes webhook:</p>\n<ul>\n<li>The wiki needs to run on <a href=\"https://www.mediawiki.org/wiki/MediaWiki_1.30\" target=\"_blank\">MediaWiki 1.30</a> or higher.</li>\n<li>The system message <code class=\"user-select\">MediaWiki:Custom-RcGcDw</code> needs to be set to the Discord server id <code class=\"user-select\" id=\"server-id\"></code>.</li>\n</ul>",
         "form": {
+            "avatar": "Webhook avatar:",
+            "avatar_preview": "Preview",
             "channel": "Channel:",
             "confirm": "Do you really want to delete the recent changes webhook?",
             "display": "Display mode:",
@@ -155,6 +161,7 @@
             "feeds": "Feeds based changes:",
             "feeds_only": "Only feeds based changes:",
             "lang": "Language:",
+            "name": "Webhook name:",
             "new": "New Recent Changes Webhook",
             "select_channel": "-- Select a Channel --",
             "wiki": "Wiki:",

+ 7 - 2
dashboard/index.js

@@ -115,6 +115,13 @@ const server = http.createServer( (req, res) => {
 		}
 	}
 
+	var reqURL = new URL(req.url, process.env.dashboard);
+
+	if ( req.method === 'HEAD' && files.has(reqURL.pathname) ) {
+		let file = files.get(reqURL.pathname);
+		res.writeHead(200, {'Content-Type': file.contentType});
+		return res.end();
+	}
 	if ( req.method !== 'GET' ) {
 		let body = '<img width="400" src="https://http.cat/418"><br><strong>' + http.STATUS_CODES[418] + '</strong>';
 		res.writeHead(418, {
@@ -125,8 +132,6 @@ const server = http.createServer( (req, res) => {
 		return res.end();
 	}
 
-	var reqURL = new URL(req.url, process.env.dashboard);
-
 	if ( reqURL.pathname === '/oauth/mw' ) {
 		return pages.verify(res, reqURL.searchParams);
 	}

+ 91 - 12
dashboard/rcscript.js

@@ -11,10 +11,17 @@ const display_types = [
 	'image',
 	'diff'
 ];
+const avatar_content_types = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
 
 const fieldset = {
 	channel: '<label for="wb-settings-channel">Channel:</label>'
 	+ '<select id="wb-settings-channel" name="channel" required></select>',
+	name: '<label for="wb-settings-name">Webhook name:</label>'
+	+ '<input type="text" id="wb-settings-name" name="name" minlength="2" maxlength="32" autocomplete="on">',
+	avatar: '<label for="wb-settings-avatar">Webhook avatar:</label>'
+	+ '<input type="url" id="wb-settings-avatar" name="avatar" list="wb-settings-avatar-list" required autocomplete="url">'
+	+ '<datalist id="wb-settings-avatar-list"></datalist>'
+	+ '<button type="button" id="wb-settings-avatar-preview">Preview</button>',
 	wiki: '<label for="wb-settings-wiki">Wiki:</label>'
 	+ '<input type="url" id="wb-settings-wiki" name="wiki" list="wb-settings-wiki-list" required autocomplete="url">'
 	+ '<datalist id="wb-settings-wiki-list"></datalist>'
@@ -63,6 +70,8 @@ const fieldset = {
  * @param {Object} settings - The current settings
  * @param {Boolean} settings.patreon
  * @param {String} [settings.channel]
+ * @param {String} [settings.name]
+ * @param {String} [settings.avatar]
  * @param {String} settings.wiki
  * @param {String} settings.lang
  * @param {Number} settings.display
@@ -115,6 +124,21 @@ function createForm($, header, dashboardLang, settings, guildChannels, allWikis)
 		$(`<option id="wb-settings-channel-${settings.channel}">`).val(settings.channel).attr('selected', '').text(settings.channel)
 	);
 	fields.push(channel);
+	let webhook_name = $('<div>').append(fieldset.name);
+	webhook_name.find('label').text(dashboardLang.get('rcscript.form.name'));
+	webhook_name.find('#wb-settings-name').val(settings.name);
+	fields.push(webhook_name);
+	let avatar = $('<div>').append(fieldset.avatar);
+	avatar.find('label').text(dashboardLang.get('rcscript.form.avatar'));
+	avatar.find('#wb-settings-avatar-preview').text(dashboardLang.get('rcscript.form.avatar_preview'));
+	avatar.find('#wb-settings-avatar').val(( settings.avatar || '' ));
+	if ( settings.avatar ) avatar.find('#wb-settings-avatar').attr('size', settings.avatar.length + 10);
+	else avatar.find('#wb-settings-avatar').attr('required', null);
+	avatar.find('#wb-settings-avatar-list').append(
+		$(`<option>`).val(new URL('/src/icon.png', process.env.dashboard).href),
+		( settings.avatar ? $(`<option>`).val(settings.avatar) : null )
+	);
+	fields.push(avatar);
 	let wiki = $('<div>').append(fieldset.wiki);
 	wiki.find('label').text(dashboardLang.get('rcscript.form.wiki'));
 	wiki.find('#wb-settings-wiki-check').text(dashboardLang.get('rcscript.form.wiki_check'));
@@ -199,11 +223,19 @@ function dashboard_rcscript(res, $, guild, args, dashboardLang) {
 				if ( !response.body?.channel_id ) {
 					console.log( '- Dashboard: ' + response.statusCode + ': Error while getting the webhook: ' + response.body?.message );
 					row.channel = 'UNKNOWN';
+					row.name = 'UNKNOWN';
+					row.avatar = '';
+				}
+				else {
+					row.channel = response.body.channel_id;
+					row.name = response.body.name;
+					row.avatar = ( response.body.avatar ? `https://cdn.discordapp.com/avatars/${response.body.id}/${response.body.avatar}` : '' );
 				}
-				else row.channel = response.body.channel_id;
 			}, error => {
 				console.log( '- Dashboard: Error while getting the webhook: ' + error );
 				row.channel = 'UNKNOWN';
+				row.name = 'UNKNOWN';
+				row.avatar = '';
 			} );
 		} )).finally( () => {
 			let suffix = ( args[0] === 'owner' ? '?owner=true' : '' );
@@ -268,6 +300,8 @@ function dashboard_rcscript(res, $, guild, args, dashboardLang) {
  * @param {String|Number} type - The setting to change
  * @param {Object} settings - The new settings
  * @param {String} settings.channel
+ * @param {String} [settings.name]
+ * @param {String} [settings.avatar]
  * @param {String} settings.wiki
  * @param {String} settings.lang
  * @param {Number} settings.display
@@ -294,6 +328,9 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 		if ( type === 'new' && !userSettings.guilds.isMember.get(guild).channels.some( channel => {
 			return ( channel.id === settings.channel && !channel.isCategory );
 		} ) ) return res(`/guild/${guild}/rcscript/new`, 'savefail');
+		settings.name = ( settings.name || '' ).trim();
+		if ( settings.name.length < 2 ) settings.name = '';
+		if ( !settings.avatar || !/^https?:\/\//.test(settings.avatar) ) settings.avatar = '';
 	}
 	if ( settings.delete_settings && type === 'new' ) {
 		return res(`/guild/${guild}/rcscript/new`, 'savefail');
@@ -357,7 +394,16 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 				if ( body.query.allmessages[0]['*'] !== guild ) {
 					return res(`/guild/${guild}/rcscript/new`, 'sysmessage', guild, wiki.toLink('MediaWiki:Custom-RcGcDw', 'action=edit'));
 				}
-				return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rows:[block]}) => {
+				return Promise.all([
+					db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ),
+					( settings.avatar ? got.head( settings.avatar ).then( headresponse => {
+						if ( avatar_content_types.includes( headresponse.headers?.['content-type'] ) ) return;
+						settings.avatar = '';
+					}, error => {
+						console.log( '- Dashboard: Error while checking for the HEAD: ' + error );
+						settings.avatar = '';
+					} ) : null )
+				]).then( ([{rows:[block]}]) => {
 					if ( block ) {
 						console.log( `- Dashboard: ${wiki.href} is blocked: ${block.reason}` );
 						return res(`/guild/${guild}/rcscript/new`, 'wikiblocked', body.query.general.sitename, block.reason);
@@ -390,7 +436,8 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 							type: 'createWebhook',
 							guild: guild,
 							channel: settings.channel,
-							name: ( body.query.allmessages[1]['*'] || 'Recent changes' ),
+							name: ( settings.name || body.query.allmessages[1]['*'] || 'Recent changes' ),
+							avatar: settings.avatar,
 							reason: lang.get('rcscript.audit_reason', wiki.href),
 							text: webhook_lang.get('created', body.query.general.sitename) + ( enableFeeds && settings.feeds_only ? '' : `\n<${wiki.toLink(body.query.pages['-1'].title)}>` ) + ( enableFeeds ? `\n<${wiki.href}f>` : '' )
 						} ).then( webhook => {
@@ -405,6 +452,8 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 								res(`/guild/${guild}/rcscript/${configid}`, 'save');
 								var text = lang.get('rcscript.dashboard.added', `<@${userSettings.user.id}>`, configid);
 								text += `\n${lang.get('rcscript.channel')} <#${settings.channel}>`;
+								text += `\n${lang.get('rcscript.name')} \`${( settings.name || body.query.allmessages[1]['*'] || 'Recent changes' )}\``;
+								if ( settings.avatar ) text += `\n${lang.get('rcscript.avatar')} <${settings.avatar}>`;
 								text += `\n${lang.get('rcscript.wiki')} <${wiki.href}>`;
 								text += `\n${lang.get('rcscript.lang')} \`${allLangs.names[settings.lang]}\``;
 								text += `\n${lang.get('rcscript.display')} \`${display_types[settings.display]}\``;
@@ -458,6 +507,8 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 				return res(`/guild/${guild}/rcscript/${type}`, 'savefail');
 			}
 			row.channel = wresponse.body.channel_id;
+			row.name = wresponse.body.name;
+			row.avatar = ( wresponse.body.avatar ? `https://cdn.discordapp.com/avatars/${wresponse.body.id}/${wresponse.body.avatar}` : '' );
 			var newChannel = false;
 			if ( settings.save_settings && row.channel !== settings.channel ) {
 				if ( !userSettings.guilds.isMember.get(guild).channels.some( channel => {
@@ -519,6 +570,7 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 						} );
 						var text = lang.get('rcscript.dashboard.removed', `<@${userSettings.user.id}>`, type);
 						text += `\n${lang.get('rcscript.channel')} <#${row.channel}>`;
+						text += `\n${lang.get('rcscript.name')} \`${row.name}\``;
 						text += `\n${lang.get('rcscript.wiki')} <${row.wiki}>`;
 						text += `\n${lang.get('rcscript.lang')} \`${allLangs.names[row.lang]}\``;
 						text += `\n${lang.get('rcscript.display')} \`${display_types[row.display]}\``;
@@ -545,6 +597,8 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 				}
 				var hasDiff = false;
 				if ( newChannel ) hasDiff = true;
+				if ( settings.name && row.name !== settings.name ) hasDiff = true;
+				if ( settings.avatar && row.avatar !== settings.avatar ) hasDiff = true;
 				if ( row.wiki !== settings.wiki ) hasDiff = true;
 				if ( row.lang !== settings.lang ) hasDiff = true;
 				if ( row.display !== settings.display ) hasDiff = true;
@@ -584,7 +638,16 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 					if ( row.wiki !== wiki.href && body.query.allmessages[0]['*'] !== guild ) {
 						return res(`/guild/${guild}/rcscript/${type}`, 'sysmessage', guild, wiki.toLink('MediaWiki:Custom-RcGcDw', 'action=edit'));
 					}
-					return db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ).then( ({rows:[block]}) => {
+					return Promise.all([
+						db.query( 'SELECT reason FROM blocklist WHERE wiki = $1', [wiki.href] ),
+						( settings.avatar && row.avatar !== settings.avatar ? got.head( settings.avatar ).then( headresponse => {
+							if ( avatar_content_types.includes( headresponse.headers?.['content-type'] ) ) return;
+							settings.avatar = '';
+						}, error => {
+							console.log( '- Dashboard: Error while checking for the HEAD: ' + error );
+							settings.avatar = '';
+						} ) : null )
+					]).then( ([{rows:[block]}]) => {
 						if ( block ) {
 							console.log( `- Dashboard: ${wiki.href} is blocked: ${block.reason}` );
 							return res(`/guild/${guild}/rcscript/${type}`, 'wikiblocked', body.query.general.sitename, block.reason);
@@ -637,6 +700,7 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 							}
 							db.query( sql + ' WHERE webhook = $1', sqlargs ).then( () => {
 								console.log( `- Dashboard: RcGcDw successfully updated: ${guild}#${type}` );
+								var webhook_changes = {};
 								var lang = new Lang(row.mainlang);
 								var webhook_lang = new Lang(settings.lang, 'rcscript.webhook');
 								var diff = [];
@@ -645,6 +709,17 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 								if ( newChannel ) {
 									diff.push(lang.get('rcscript.channel') + ` ~~<#${row.channel}>~~ → <#${settings.channel}>`);
 									webhook_diff.push(webhook_lang.get('dashboard.channel'));
+									webhook_changes.channel = settings.channel;
+								}
+								if ( settings.name && row.name !== settings.name ) {
+									diff.push(lang.get('rcscript.name') + ` ~~\`${row.name}\`~~ → \`${settings.name}\``);
+									webhook_diff.push(webhook_lang.get('dashboard.name', settings.name));
+									webhook_changes.name = settings.name;
+								}
+								if ( settings.avatar && row.avatar !== settings.avatar ) {
+									diff.push(lang.get('rcscript.avatar') + ` <${settings.avatar}>`);
+									webhook_diff.push(webhook_lang.get('dashboard.avatar'));
+									webhook_changes.avatar = settings.avatar;
 								}
 								if ( row.wiki !== wiki.href ) {
 									diff.push(lang.get('rcscript.wiki') + ` ~~<${row.wiki}>~~ → <${wiki.href}>`);
@@ -667,12 +742,14 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 									diff.push(lang.get('rcscript.feeds') + ` ~~*\`${lang.get('rcscript.' + ( row.postid === '-1' ? 'disabled' : 'enabled' ))}\`*~~ → *\`${lang.get('rcscript.' + ( enableFeeds ? 'enabled' : 'disabled' ))}\`*`);
 									webhook_diff.push(webhook_lang.get('dashboard.' + ( enableFeeds ? 'enabled_feeds' : 'disabled_feeds' )));
 								}
-								if ( newChannel ) return sendMsg( {
-									type: 'moveWebhook',
+								if ( Object.keys(webhook_changes).length ) return sendMsg( {
+									type: 'editWebhook',
 									guild: guild,
 									webhook: row.webhook,
-									channel: settings.channel,
-									reason: lang.get('rcscript.audit_reason_move'),
+									channel: webhook_changes.channel,
+									name: webhook_changes.name,
+									avatar: webhook_changes.avatar,
+									reason: lang.get('rcscript.audit_reason_edit'),
 									text: webhook_lang.get('dashboard.updated') + '\n' + webhook_diff.join('\n')
 								} ).then( webhook => {
 									if ( !webhook ) return Promise.reject();
@@ -686,15 +763,17 @@ function update_rcscript(res, userSettings, guild, type, settings) {
 										console.log( '- Dashboard: Error while notifying the guild: ' + error );
 									} );
 								}, error => {
-									console.log( '- Dashboard: Error while moving the webhook: ' + error );
+									console.log( '- Dashboard: Error while editing the webhook: ' + error );
 									return Promise.reject();
 								} ).catch( () => {
-									diff.shift();
-									webhook_diff.shift();
+									Object.keys(webhook_changes).forEach( () => {
+										diff.shift();
+										webhook_diff.shift();
+									} );
 									if ( !diff.length ) {
 										return res(`/guild/${guild}/rcscript/${type}`, 'savefail');
 									}
-									res(`/guild/${guild}/rcscript/${type}`, 'movefail');
+									res(`/guild/${guild}/rcscript/${type}`, 'webhookfail');
 									diff.shift();
 									webhook_diff.shift();
 									got.post( 'https://discord.com/api/webhooks/' + row.webhook, {

+ 7 - 0
dashboard/src/index.css

@@ -129,6 +129,7 @@ a[alt]:hover:after {
 	border-radius: 50%;
 	width: 48px;
 	height: 48px;
+	object-fit: cover;
 	display: flex;
 	align-items: center;
 	justify-content: center;
@@ -551,10 +552,16 @@ fieldset textarea {
 	color: #2e3338;
 	background-color: #ebedef;
 }
+#wb-settings-avatar-preview-img {
+	width: 128px;
+	height: 128px;
+	background: #32353b;
+}
 .wb-settings-display:first-of-type,
 .wb-settings-permission:first-of-type {
 	display: inline-block;
 }
+#wb-settings-avatar-preview-img,
 .wb-settings-display:not(:first-of-type),
 .wb-settings-permission:not(:first-of-type),
 .wb-settings-additional-select,

+ 57 - 3
dashboard/src/index.js

@@ -124,15 +124,17 @@ function toggleOption() {
 	} );
 }
 
+var divTemp = document.createElement('div');
+divTemp.innerHTML = '<input type="url" value="invalid">';
+const validationMessageInvalidURL = divTemp.firstChild.validationMessage;
+
 /** @type {HTMLInputElement} */
 const wiki = document.getElementById('wb-settings-wiki');
 if ( wiki ) {
 	wiki.addEventListener( 'input', function() {
 		if ( !/^(?:https?:)?\/\//.test(this.value) ) {
 			if ( this.validity.valid ) {
-				var divTemp = document.createElement('div');
-				divTemp.innerHTML = '<input type="url" value="invalid">';
-				this.setCustomValidity(divTemp.firstChild.validationMessage);
+				this.setCustomValidity(validationMessageInvalidURL);
 			}
 		}
 		else this.setCustomValidity('');
@@ -314,6 +316,58 @@ if ( wiki ) {
 	}
 }
 
+/** @type {HTMLInputElement} */
+const avatar = document.getElementById('wb-settings-avatar');
+if ( avatar ) {
+	avatar.addEventListener( 'input', function() {
+		if ( !/^(?:https?:)?\/\//.test(this.value) ) {
+			if ( this.validity.valid ) {
+				this.setCustomValidity(validationMessageInvalidURL);
+			}
+		}
+		else this.setCustomValidity('');
+	} );
+	/** @type {HTMLButtonElement} */
+	const avatarbutton = document.getElementById('wb-settings-avatar-preview');
+	if ( avatarbutton ) {
+		const avatarpreview = document.createElement('img');
+		avatarpreview.id = 'wb-settings-avatar-preview-img';
+		avatarpreview.classList.add('avatar');
+		const validContentTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
+		avatarbutton.onclick = function() {
+			if ( !avatar.value ) return;
+			if ( !avatar.validity.valid ) return avatar.reportValidity();
+			if ( avatar.value === avatar.defaultValue ) {
+				avatarpreview.src = avatar.value;
+				avatarbutton.after(avatarpreview);
+				return;
+			}
+			fetch( avatar.value, {
+				method: 'HEAD',
+				referrer: ''
+			} ).then( function(response) {
+				if ( !validContentTypes.includes( response.headers.get('content-type') ) ) {
+					var invalidContentType = lang('avatar.content_type').replace( /\$1/g, response.headers.get('content-type') );
+					avatar.setCustomValidity(invalidContentType + '\n' + validContentTypes.join(', ') );
+					avatar.reportValidity();
+					return console.log( 'Invalid content type:', response.headers.get('content-type') );
+				}
+				avatarpreview.src = avatar.value;
+				avatarbutton.after(avatarpreview);
+				
+			}, function(error) {
+				console.log(error);
+				avatar.setCustomValidity(lang('avatar.invalid_url'));
+				avatar.reportValidity();
+			} );
+		};
+		if ( avatar.value ) {
+			avatarpreview.src = avatar.value;
+			avatarbutton.after(avatarpreview);
+		}
+	}
+}
+
 /** @type {HTMLInputElement} */
 const logall = document.getElementById('wb-settings-flag_logall');
 if ( logall ) {

+ 4 - 4
dashboard/util.js

@@ -309,11 +309,11 @@ function createNotice($, notice, dashboardLang, args = []) {
 				note = $('<div>').text(dashboardLang.get('notice.savefail.note_' + args[0]));
 			}
 			break;
-		case 'movefail':
+		case 'webhookfail':
 			type = 'info';
-			title.text(dashboardLang.get('notice.movefail.title'));
-			text.text(dashboardLang.get('notice.movefail.text'));
-			note = $('<div>').text(dashboardLang.get('notice.movefail.note'));
+			title.text(dashboardLang.get('notice.webhookfail.title'));
+			text.text(dashboardLang.get('notice.webhookfail.text'));
+			note = $('<div>').text(dashboardLang.get('notice.webhookfail.note'));
 			break;
 		case 'refreshfail':
 			type = 'error';

+ 5 - 1
i18n/en.json

@@ -494,7 +494,8 @@
         "all_inactive": "you can't have wiki changes and feeds based changes disabled at the same time.",
         "audit_reason": "Recent changes webhook for \"$1\"",
         "audit_reason_delete": "Removed recent changes webhook",
-        "audit_reason_move": "Moved recent changes webhook",
+        "audit_reason_edit": "Updated recent changes webhook",
+        "avatar": "Webhook avatar:",
         "blocked": "this wiki has been blocked from being added as a recent changes webhook!",
         "blocked_reason": "this wiki has been blocked from being added as a recent changes webhook for `$1`!",
         "channel": "Channel:",
@@ -528,6 +529,7 @@
         "lang": "Language:",
         "max_entries": "you already reached the maximal amount of recent changes webhooks.",
         "missing": "there are no recent changes webhooks for this server yet.",
+        "name": "Webhook name:",
         "new_lang": "<new language>",
         "new_wiki": "<link to wiki>",
         "no_feeds": "the wiki for this webhook has no feeds based features, like discussions, message walls or article comments, enabled.",
@@ -545,6 +547,7 @@
             "blocked_reason": "This recent changes webhook will be deleted because the wiki has been blocked for `$1`!",
             "created": "A recent changes webhook for $1 has been added to this channel.",
             "dashboard": {
+                "avatar": "• The webhook avatar has been changed.",
                 "channel": "• The webhook has been moved to this channel.",
                 "disabled_feeds": "• The feeds based changes, like discussions, message walls and article comments, have been disabled.",
                 "disabled_rc": "• The wiki changes have been disabled.",
@@ -555,6 +558,7 @@
                 "enabled_feeds": "• The feeds based changes, like discussions, message walls and article comments, have been enabled.",
                 "enabled_rc": "• The wiki changes have been enabled.",
                 "lang": "• The language has been changed to $1.",
+                "name": "• The webhook name has been changed to \"$1\".",
                 "updated": "This recent changes webhook has been updated:",
                 "wiki": "• The wiki has been changed to $1."
             },

+ 35 - 33
main.js

@@ -102,7 +102,7 @@ if ( process.env.dashboard ) {
 						${JSON.stringify(message.data.guilds)}.map( id => {
 							if ( this.guilds.cache.has(id) ) {
 								let guild = this.guilds.cache.get(id);
-								return guild.members.fetch('${message.data.member}').then( member => {
+								return guild.members.fetch(${JSON.stringify(message.data.member)}).then( member => {
 									return {
 										patreon: global.patreons.hasOwnProperty(guild.id),
 										memberCount: guild.memberCount,
@@ -157,17 +157,17 @@ if ( process.env.dashboard ) {
 					} );
 					break;
 				case 'getMember':
-					return manager.broadcastEval(`if ( this.guilds.cache.has('${message.data.guild}') ) {
-						let guild = this.guilds.cache.get('${message.data.guild}');
-						guild.members.fetch('${message.data.member}').then( member => {
+					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
+						let guild = this.guilds.cache.get(${JSON.stringify(message.data.guild)});
+						guild.members.fetch(${JSON.stringify(message.data.member)}).then( member => {
 							var response = {
 								patreon: global.patreons.hasOwnProperty(guild.id),
 								userPermissions: member.permissions.bitfield,
 								botPermissions: guild.me.permissions.bitfield
 							};
-							if ( '${( message.data.channel || '' )}' ) {
-								let channel = guild.channels.cache.get('${message.data.channel}');
-								if ( channel?.isText() || ( response.patreon && ${message.data.allowCategory} && channel?.type === 'category' ) ) {
+							if ( ${JSON.stringify(message.data.channel)} ) {
+								let channel = guild.channels.cache.get(${JSON.stringify(message.data.channel)});
+								if ( channel?.isText() || ( response.patreon && ${JSON.stringify(message.data.allowCategory)} && channel?.type === 'category' ) ) {
 									response.userPermissions = channel.permissionsFor(member).bitfield;
 									response.botPermissions = channel.permissionsFor(guild.me).bitfield;
 									response.isCategory = ( channel.type === 'category' );
@@ -175,8 +175,8 @@ if ( process.env.dashboard ) {
 								}
 								else response.message = 'noChannel';
 							}
-							if ( '${( message.data.newchannel || '' )}' ) {
-								let newchannel = guild.channels.cache.get('${message.data.newchannel}');
+							if ( ${JSON.stringify(message.data.newchannel)} ) {
+								let newchannel = guild.channels.cache.get(${JSON.stringify(message.data.newchannel)});
 								if ( newchannel?.isText() ) {
 									response.userPermissionsNew = newchannel.permissionsFor(member).bitfield;
 									response.botPermissionsNew = newchannel.permissionsFor(guild.me).bitfield;
@@ -196,15 +196,15 @@ if ( process.env.dashboard ) {
 					} );
 					break;
 				case 'notifyGuild':
-					return manager.broadcastEval(`if ( '${( message.data.prefix || '' )}' ) {
-						global.patreons['${message.data.guild}'] = '${message.data.prefix}';
+					return manager.broadcastEval(`if ( ${JSON.stringify(message.data.prefix)} ) {
+						global.patreons[${JSON.stringify(message.data.guild)}] = ${JSON.stringify(message.data.prefix)};
 					}
-					if ( '${( message.data.voice || '' )}' && global.voice.hasOwnProperty('${message.data.guild}') ) {
-						global.voice['${message.data.guild}'] = '${message.data.voice}';
+					if ( ${JSON.stringify(message.data.voice)} && global.voice.hasOwnProperty(${JSON.stringify(message.data.guild)}) ) {
+						global.voice[${JSON.stringify(message.data.guild)}] = ${JSON.stringify(message.data.voice)};
 					}
-					if ( this.guilds.cache.has('${message.data.guild}') ) {
-						let channel = this.guilds.cache.get('${message.data.guild}').publicUpdatesChannel;
-						if ( channel ) channel.send( \`${message.data.text.replace( /`/g, '\\`' )}\`, {
+					if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
+						let channel = this.guilds.cache.get(${JSON.stringify(message.data.guild)}).publicUpdatesChannel;
+						if ( channel ) channel.send( ${JSON.stringify(message.data.text)}, {
 							embed: ${JSON.stringify(message.data.embed)},
 							files: ${JSON.stringify(message.data.file)},
 							allowedMentions: {parse: []}, split: true
@@ -216,14 +216,14 @@ if ( process.env.dashboard ) {
 					} );
 					break;
 				case 'createWebhook':
-					return manager.broadcastEval(`if ( this.guilds.cache.has('${message.data.guild}') ) {
-						let channel = this.guilds.cache.get('${message.data.guild}').channels.cache.get('${message.data.channel}');
-						if ( channel ) channel.createWebhook( \`${message.data.name.replace( /`/g, '\\`' )}\`, {
-							avatar: this.user.displayAvatarURL({format:'png',size:4096}),
-							reason: \`${message.data.reason.replace( /`/g, '\\`' )}\`
+					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
+						let channel = this.guilds.cache.get(${JSON.stringify(message.data.guild)}).channels.cache.get(${JSON.stringify(message.data.channel)});
+						if ( channel ) channel.createWebhook( ${JSON.stringify(message.data.name)}, {
+							avatar: ( ${JSON.stringify(message.data.avatar)} || this.user.displayAvatarURL({format:'png',size:4096}) ),
+							reason: ${JSON.stringify(message.data.reason)}
 						} ).then( webhook => {
 							console.log( '- Dashboard: Webhook successfully created: ${message.data.guild}#${message.data.channel}' );
-							webhook.send( \`${message.data.text.replace( /`/g, '\\`' )}\` ).catch(log_error);
+							webhook.send( ${JSON.stringify(message.data.text)} ).catch(log_error);
 							return webhook.id + '/' + webhook.token;
 						}, error => {
 							console.log( '- Dashboard: Error while creating the webhook: ' + error );
@@ -236,20 +236,22 @@ if ( process.env.dashboard ) {
 						return dashboard.send( {id: message.id, data} );
 					} );
 					break;
-				case 'moveWebhook':
-					return manager.broadcastEval(`if ( this.guilds.cache.has('${message.data.guild}') ) {
-						this.fetchWebhook(...'${message.data.webhook}'.split('/')).then( webhook => {
-							return webhook.edit( {
-								channel: '${message.data.channel}'
-							}, \`${message.data.reason.replace( /`/g, '\\`' )}\` ).then( newwebhook => {
-								console.log( '- Dashboard: Webhook successfully moved: ${message.data.guild}#${message.data.channel}' );
-								webhook.send( \`${message.data.text.replace( /`/g, '\\`' )}\` ).catch(log_error);
+				case 'editWebhook':
+					return manager.broadcastEval(`if ( this.guilds.cache.has(${JSON.stringify(message.data.guild)}) ) {
+						this.fetchWebhook(...${JSON.stringify(message.data.webhook.split('/'))}).then( webhook => {
+							var changes = {};
+							if ( ${JSON.stringify(message.data.channel)} ) changes.channel = ${JSON.stringify(message.data.channel)};
+							if ( ${JSON.stringify(message.data.name)} ) changes.name = ${JSON.stringify(message.data.name)};
+							if ( ${JSON.stringify(message.data.avatar)} ) changes.avatar = ${JSON.stringify(message.data.avatar)};
+							return webhook.edit( changes, ${JSON.stringify(message.data.reason)} ).then( newwebhook => {
+								console.log( '- Dashboard: Webhook successfully edited: ${message.data.guild}#' + ( ${JSON.stringify(message.data.channel)} || webhook.channelID ) );
+								webhook.send( ${JSON.stringify(message.data.text)} ).catch(log_error);
 								return true;
 							}, error => {
-								console.log( '- Dashboard: Error while moving the webhook: ' + error );
+								console.log( '- Dashboard: Error while editing the webhook: ' + error );
 							} );
 						}, error => {
-							console.log( '- Dashboard: Error while moving the webhook: ' + error );
+							console.log( '- Dashboard: Error while editing the webhook: ' + error );
 						} );
 					}`, shardIDForGuildID(message.data.guild, manager.totalShards)).then( result => {
 						data.response = result;
@@ -260,7 +262,7 @@ if ( process.env.dashboard ) {
 					} );
 					break;
 				case 'verifyUser':
-					return manager.broadcastEval(`global.verifyOauthUser('${message.data.state}', '${message.data.access_token}')`, message.data.state.split(' ')[1][0]).catch( error => {
+					return manager.broadcastEval(`global.verifyOauthUser(${JSON.stringify(message.data.state)}, ${JSON.stringify(message.data.access_token)})`, message.data.state.split(' ')[1][0]).catch( error => {
 						data.error = error.toString();
 					} ).finally( () => {
 						return dashboard.send( {id: message.id, data} );