Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add commands for upper staff to add custom avatars #5515

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions server/chat-plugins/customavatars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Original plugin from https://github.com/CreaturePhil/Showdown-Boilerplate/blob/master/chat-plugins/customavatar.js.
// Credits to CreaturePhil and the other listed contributors.
// updated for the main server by Maxalexanderpi and Hoeenhero.
*/
'use strict';

/** @type {typeof import('../../lib/fs').FS} */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the wrong place, it should be above the importing of 'FS'.

const path = require('path');
const fs = require('fs');
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved
const https = require('https');

const AVATAR_PATH = 'config/avatars/';

const VALID_EXTENSIONS = ['.png'];
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved

function downloadImage(image_url, name, extension) {
let req = https.get(image_url, res => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably be returning a promise

res.setEncoding('binary');
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved
res.on('response', response => {
if (response.statusCode !== 200) return;
let type = response.headers['content-type'].split('/');
if (type[0] !== 'image') return;

response.pipe(fs(AVATAR_PATH + name + extension).createWriteStream());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably be returning a promise

Resolve the promise on finish event of the fs write stream.

});
});
req.on('error', e => {
console.error(e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure this is the correct error handling mechanism

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to throw the error to crashlogger in hindsight.

I need to review the plugin as a whole when I have time, haven't done much other than offer advice on a few issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling and logging seems to be quite badly implemented.

});
req.end();
}
function loadCustomAvatars() {
fs.readdir(AVATAR_PATH, (err, files) => {
if (err) console.log("Error loading custom avatars: " + err);
if (!files) files = [];
files
.filter(file => VALID_EXTENSIONS.includes(path.extname(file)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably blacklist __proto__ and constructor

.forEach(file => {
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved
let name = path.basename(file, path.extname(file));
Config.customavatars[name] = file;
});
});
}
loadCustomAvatars();

exports.commands = {
customavatar: {
add(target, room, user) {
if (!this.can('avatar')) return false;
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved
let parts = target.split(',').map(param => param.trim());
if (parts.length < 2) return this.parse('/help customavatar');

let name = toID(parts[0]);
let avatarUrl = parts[1];
if (!/^https?:\/\//i.test(avatarUrl)) avatarUrl = 'http://' + avatarUrl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URLs don't necessarily end in the extension of the actual file they point at

let ext = path.extname(avatarUrl);

if (!VALID_EXTENSIONS.includes(ext)) {
return this.errorReply("Image url must end in a .png extension.");
}

Config.customavatars[name] = name + ext;

downloadImage(avatarUrl, name, ext);
this.sendReply(`|raw|${name}${name.endsWith('s') ? "'" : "'s"} avatar was successfully set. Avatar:<br /><img src="${avatarUrl}" width="80" height="80">);
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved
Monitor.adminlog(name + "'s avatar was successfully set by " + user.name + ".");
if (Users(name)) Users(name).popup("|html|Upper staff have set your custom avatar.<br /><img src='" + avatarUrl + "' width='80' height='80'><br /> Refresh your page if you don't see it.");
},

remove(target, room, user) {
if (!this.can('')) return false;
mia-pi-git marked this conversation as resolved.
Show resolved Hide resolved

let userid = toID(target);
let image = Config.customavatars[userid];

if (!image) return this.errorReply(target + " does not have a custom avatar.");

delete Config.customavatars[userid];
fs.unlink(AVATAR_PATH + image, err => {
if (err && err.code === 'ENOENT') {
return this.errorReply(target + "'s avatar does not exist.");
} else if (err) {
console.error(err);
}

if (Users(userid)) Users(userid).popup("Upper staff have removed your custom avatar.");
this.sendReply(target + "'s avatar has been successfully removed.");
Monitor.adminlog(target + "'s avatar has been successfully removed.");
});
},

customavatarhelp: 'help',
help(target, room, user) {
this.parse('/help customavatar');
},
},

customavatarhelp: [
"Commands for /customavatar are:",
"/customavatar add [username], [image link] - Set a user's custom avatar. Requires: & ~",
"/customavatar remove [username] - Delete a user's custom avatar. Requires: & ~"],
};