Merge pull request #1920 from thelounge/xpaw/more-eslint
Enforce padding-line-between-statements
This commit is contained in:
commit
1ce2792fc4
@ -48,6 +48,18 @@ rules:
|
||||
no-var: error
|
||||
object-curly-spacing: [error, never]
|
||||
padded-blocks: [error, never]
|
||||
padding-line-between-statements:
|
||||
- error
|
||||
- blankLine: always
|
||||
prev:
|
||||
- block
|
||||
- block-like
|
||||
next: "*"
|
||||
- blankLine: always
|
||||
prev: "*"
|
||||
next:
|
||||
- block
|
||||
- block-like
|
||||
prefer-const: error
|
||||
prefer-rest-params: error
|
||||
prefer-spread: error
|
||||
|
@ -50,6 +50,7 @@ const nicksStrategy = {
|
||||
match: /\B(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/,
|
||||
search(term, callback) {
|
||||
term = term.slice(1);
|
||||
|
||||
if (term[0] === "@") {
|
||||
callback(completeNicks(term.slice(1), true)
|
||||
.map((val) => ["@" + val[0], "@" + val[1]]));
|
||||
@ -122,6 +123,7 @@ const foregroundColorStrategy = {
|
||||
post: "</b>",
|
||||
}).rendered];
|
||||
}
|
||||
|
||||
return i;
|
||||
});
|
||||
|
||||
@ -150,6 +152,7 @@ const backgroundColorStrategy = {
|
||||
post: "</b>",
|
||||
}).rendered];
|
||||
}
|
||||
|
||||
return pair;
|
||||
})
|
||||
.map((pair) => pair.concat(match[1])); // Needed to pass fg color to `template`...
|
||||
@ -268,9 +271,11 @@ function completeNicks(word, isFuzzy) {
|
||||
}
|
||||
|
||||
const words = users.data("nicks");
|
||||
|
||||
if (isFuzzy) {
|
||||
return fuzzyGrep(word, words);
|
||||
}
|
||||
|
||||
return $.grep(
|
||||
words,
|
||||
(w) => !w.toLowerCase().indexOf(word)
|
||||
@ -291,6 +296,7 @@ function completeChans(word) {
|
||||
.find(".chan")
|
||||
.each(function() {
|
||||
const self = $(this);
|
||||
|
||||
if (!self.hasClass("lobby")) {
|
||||
words.push(self.attr("aria-label"));
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ function updateText(condensed, addedTypes) {
|
||||
});
|
||||
|
||||
let text = strings.pop();
|
||||
|
||||
if (strings.length) {
|
||||
text = strings.join(", ") + ", and " + text;
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ sidebar.on("submit", ".join-form", function() {
|
||||
const key = form.find("input[name='key']");
|
||||
const keyString = key.val();
|
||||
const chan = utils.findCurrentNetworkChan(channelString);
|
||||
|
||||
if (chan.length) {
|
||||
chan.trigger("click");
|
||||
} else {
|
||||
@ -76,6 +77,7 @@ sidebar.on("submit", ".join-form", function() {
|
||||
target: form.prev().data("id"),
|
||||
});
|
||||
}
|
||||
|
||||
closeForm(form.closest(".network"));
|
||||
return false;
|
||||
});
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Generates a string from "color-1" to "color-32" based on an input string
|
||||
module.exports = function(str) {
|
||||
let hash = 0;
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash += str.charCodeAt(i);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ function fill(existingEntries, text) {
|
||||
end: textSegment.start,
|
||||
});
|
||||
}
|
||||
|
||||
position = textSegment.end;
|
||||
return acc;
|
||||
}, []);
|
||||
|
@ -11,6 +11,7 @@ function findNames(text, users) {
|
||||
}
|
||||
|
||||
let match;
|
||||
|
||||
while ((match = nickRegExp.exec(text))) {
|
||||
if (users.indexOf(match[1]) > -1) {
|
||||
result.push({
|
||||
|
@ -46,6 +46,7 @@ function parseStyle(text) {
|
||||
strikethrough = false;
|
||||
monospace = false;
|
||||
};
|
||||
|
||||
resetStyle();
|
||||
|
||||
// When called, this "closes" the current fragment by adding an entry to the
|
||||
@ -111,9 +112,11 @@ function parseStyle(text) {
|
||||
|
||||
if (colorCodes) {
|
||||
textColor = Number(colorCodes[1]);
|
||||
|
||||
if (colorCodes[2]) {
|
||||
bgColor = Number(colorCodes[2]);
|
||||
}
|
||||
|
||||
// Color code length is > 1, so bump the current position cursor by as
|
||||
// much (and reset the start cursor for the current text block as well)
|
||||
position += colorCodes[0].length;
|
||||
@ -123,6 +126,7 @@ function parseStyle(text) {
|
||||
textColor = undefined;
|
||||
bgColor = undefined;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HEX_COLOR:
|
||||
@ -132,9 +136,11 @@ function parseStyle(text) {
|
||||
|
||||
if (colorCodes) {
|
||||
hexColor = colorCodes[1].toUpperCase();
|
||||
|
||||
if (colorCodes[2]) {
|
||||
hexBgColor = colorCodes[2].toUpperCase();
|
||||
}
|
||||
|
||||
// Color code length is > 1, so bump the current position cursor by as
|
||||
// much (and reset the start cursor for the current text block as well)
|
||||
position += colorCodes[0].length;
|
||||
@ -154,6 +160,7 @@ function parseStyle(text) {
|
||||
textColor = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
case ITALIC:
|
||||
emitFragment();
|
||||
italic = !italic;
|
||||
@ -194,12 +201,14 @@ function prepare(text) {
|
||||
.reduce((prev, curr) => {
|
||||
if (prev.length) {
|
||||
const lastEntry = prev[prev.length - 1];
|
||||
|
||||
if (properties.every((key) => curr[key] === lastEntry[key])) {
|
||||
lastEntry.text += curr.text;
|
||||
lastEntry.end += curr.text.length;
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
return prev.concat([curr]);
|
||||
}, []);
|
||||
}
|
||||
|
@ -13,24 +13,31 @@ const colorClass = require("./colorClass");
|
||||
// Create an HTML `span` with styling information for a given fragment
|
||||
function createFragment(fragment) {
|
||||
const classes = [];
|
||||
|
||||
if (fragment.bold) {
|
||||
classes.push("irc-bold");
|
||||
}
|
||||
|
||||
if (fragment.textColor !== undefined) {
|
||||
classes.push("irc-fg" + fragment.textColor);
|
||||
}
|
||||
|
||||
if (fragment.bgColor !== undefined) {
|
||||
classes.push("irc-bg" + fragment.bgColor);
|
||||
}
|
||||
|
||||
if (fragment.italic) {
|
||||
classes.push("irc-italic");
|
||||
}
|
||||
|
||||
if (fragment.underline) {
|
||||
classes.push("irc-underline");
|
||||
}
|
||||
|
||||
if (fragment.strikethrough) {
|
||||
classes.push("irc-strikethrough");
|
||||
}
|
||||
|
||||
if (fragment.monospace) {
|
||||
classes.push("irc-monospace");
|
||||
}
|
||||
@ -89,6 +96,7 @@ module.exports = function parse(text, users) {
|
||||
if (intersection) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
return prev.concat([curr]);
|
||||
}, []);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
(function() {
|
||||
var displayReload = function displayReload() {
|
||||
var loadingReload = document.getElementById("loading-reload");
|
||||
|
||||
if (loadingReload) {
|
||||
loadingReload.style.display = "block";
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ $(function() {
|
||||
});
|
||||
|
||||
const channel = target.closest(".chan");
|
||||
|
||||
if (utils.isOpInChannel(channel) && channel.data("type") === "channel") {
|
||||
output += templates.contextmenu_divider();
|
||||
output += templates.contextmenu_item({
|
||||
@ -127,6 +128,7 @@ $(function() {
|
||||
data: target.data("target"),
|
||||
});
|
||||
output += templates.contextmenu_divider();
|
||||
|
||||
if (target.hasClass("lobby")) {
|
||||
output += templates.contextmenu_item({
|
||||
class: "list",
|
||||
@ -141,6 +143,7 @@ $(function() {
|
||||
data: target.data("id"),
|
||||
});
|
||||
}
|
||||
|
||||
if (target.hasClass("channel")) {
|
||||
output += templates.contextmenu_item({
|
||||
class: "list",
|
||||
@ -149,6 +152,7 @@ $(function() {
|
||||
data: target.data("id"),
|
||||
});
|
||||
}
|
||||
|
||||
output += templates.contextmenu_item({
|
||||
class: "close",
|
||||
action: "close",
|
||||
@ -213,6 +217,7 @@ $(function() {
|
||||
});
|
||||
|
||||
let focus = $.noop;
|
||||
|
||||
if (!("ontouchstart" in window || navigator.maxTouchPoints > 0)) {
|
||||
focus = function() {
|
||||
if (chat.find(".active").hasClass("chan")) {
|
||||
@ -250,6 +255,7 @@ $(function() {
|
||||
if (text.charAt(0) === "/") {
|
||||
const args = text.substr(1).split(" ");
|
||||
const cmd = args.shift().toLowerCase();
|
||||
|
||||
if (typeof utils.inputCommands[cmd] === "function" && utils.inputCommands[cmd](args)) {
|
||||
return;
|
||||
}
|
||||
@ -336,6 +342,7 @@ $(function() {
|
||||
const openWindow = function openWindow(e, data) {
|
||||
const self = $(this);
|
||||
const target = self.data("target");
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
@ -397,13 +404,16 @@ $(function() {
|
||||
|
||||
let title = $(document.body).data("app-name");
|
||||
const chanTitle = chan.attr("aria-label");
|
||||
|
||||
if (chanTitle.length > 0) {
|
||||
title = `${chanTitle} — ${title}`;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
|
||||
const type = chan.data("type");
|
||||
let placeholder = "";
|
||||
|
||||
if (type === "channel" || type === "query") {
|
||||
placeholder = `Write to ${chanTitle}`;
|
||||
}
|
||||
@ -418,6 +428,7 @@ $(function() {
|
||||
}
|
||||
|
||||
const chanChat = chan.find(".chat");
|
||||
|
||||
if (chanChat.length > 0 && type !== "special") {
|
||||
chanChat.sticky();
|
||||
}
|
||||
@ -446,6 +457,7 @@ $(function() {
|
||||
if (data && data.pushState === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = {};
|
||||
|
||||
if (self.prop("id")) {
|
||||
@ -486,10 +498,12 @@ $(function() {
|
||||
if (chan.hasClass("lobby")) {
|
||||
cmd = "/quit";
|
||||
const server = chan.find(".name").html();
|
||||
|
||||
if (!confirm("Disconnect from " + server + "?")) { // eslint-disable-line no-alert
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit("input", {
|
||||
target: chan.data("id"),
|
||||
text: cmd,
|
||||
@ -602,6 +616,7 @@ $(function() {
|
||||
if ($("body").hasClass("public") && (window.location.hash === "#connect" || window.location.hash === "")) {
|
||||
$("#connect").one("show", function() {
|
||||
const params = URI(document.location.search).search(true);
|
||||
|
||||
// Possible parameters: name, host, port, password, tls, nick, username, realname, join
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#Iterating_over_own_properties_only
|
||||
for (let key in params) {
|
||||
@ -611,6 +626,7 @@ $(function() {
|
||||
key = key.replace(/\W/g, "");
|
||||
|
||||
const element = $("#connect input[name='" + key + "']");
|
||||
|
||||
// if the element exists, it isn't disabled, and it isn't hidden
|
||||
if (element.length > 0 && !element.is(":disabled") && !element.is(":hidden")) {
|
||||
if (element.is(":checkbox")) {
|
||||
@ -647,10 +663,12 @@ $(function() {
|
||||
// This should always be 24h later but re-computing exact value just in case
|
||||
setTimeout(updateDateMarkers, msUntilNextDay());
|
||||
}
|
||||
|
||||
setTimeout(updateDateMarkers, msUntilNextDay());
|
||||
|
||||
window.addEventListener("popstate", (e) => {
|
||||
const {state} = e;
|
||||
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ module.exports.initialize = () => {
|
||||
if (Notification.permission === "default" && desktopNotificationsCheckbox.prop("checked")) {
|
||||
desktopNotificationsCheckbox.prop("checked", false);
|
||||
}
|
||||
|
||||
desktopNotificationsCheckbox.prop("disabled", false);
|
||||
warningBlocked.hide();
|
||||
}
|
||||
@ -148,6 +149,7 @@ module.exports.initialize = () => {
|
||||
const highlightsTokens = options.highlights.map(function(h) {
|
||||
return escapeRegExp(h);
|
||||
});
|
||||
|
||||
if (highlightsTokens && highlightsTokens.length) {
|
||||
module.exports.highlightsRE = new RegExp("\\b(?:" + highlightsTokens.join("|") + ")\\b", "i");
|
||||
} else {
|
||||
|
@ -141,19 +141,23 @@ function openImageViewer(link, {pushState = true} = {}) {
|
||||
// Previous image
|
||||
let previousImage = link.closest(".preview").prev(".preview")
|
||||
.find(".toggle-content.show .toggle-thumbnail").last();
|
||||
|
||||
if (!previousImage.length) {
|
||||
previousImage = link.closest(".msg").prevAll()
|
||||
.find(".toggle-content.show .toggle-thumbnail").last();
|
||||
}
|
||||
|
||||
previousImage.addClass("previous-image");
|
||||
|
||||
// Next image
|
||||
let nextImage = link.closest(".preview").next(".preview")
|
||||
.find(".toggle-content.show .toggle-thumbnail").first();
|
||||
|
||||
if (!nextImage.length) {
|
||||
nextImage = link.closest(".msg").nextAll()
|
||||
.find(".toggle-content.show .toggle-thumbnail").first();
|
||||
}
|
||||
|
||||
nextImage.addClass("next-image");
|
||||
|
||||
imageViewer.html(templates.image_viewer({
|
||||
@ -173,12 +177,14 @@ function openImageViewer(link, {pushState = true} = {}) {
|
||||
// History management
|
||||
if (pushState) {
|
||||
let clickTarget = "";
|
||||
|
||||
// Images can be in a message (channel URL previews) or not (window URL
|
||||
// preview, e.g. changelog). This is sub-optimal and needs improvement to
|
||||
// make image preview more generic and not specific for channel previews.
|
||||
if (link.closest(".msg").length > 0) {
|
||||
clickTarget = `#${link.closest(".msg").prop("id")} `;
|
||||
}
|
||||
|
||||
clickTarget += `a.toggle-thumbnail[href="${link.prop("href")}"] img`;
|
||||
history.pushState({clickTarget}, null, null);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ const socket = require("../socket");
|
||||
|
||||
socket.on("change-password", function(data) {
|
||||
const passwordForm = $("#change-password");
|
||||
|
||||
if (data.error || data.success) {
|
||||
const message = data.success ? data.success : data.error;
|
||||
const feedback = passwordForm.find(".feedback");
|
||||
|
@ -24,6 +24,7 @@ socket.on("more", function(data) {
|
||||
// Remove the date-change marker we put at the top, because it may
|
||||
// not actually be a date change now
|
||||
const children = $(chan).children();
|
||||
|
||||
if (children.eq(0).hasClass("date-marker-container")) { // Check top most child
|
||||
children.eq(0).remove();
|
||||
} else if (children.eq(1).hasClass("date-marker-container")) {
|
||||
|
@ -12,6 +12,7 @@ const chat = $("#chat");
|
||||
const sidebar = $("#sidebar");
|
||||
|
||||
let pop;
|
||||
|
||||
try {
|
||||
pop = new Audio();
|
||||
pop.src = "audio/pop.ogg";
|
||||
@ -69,6 +70,7 @@ function processReceivedMessage(data) {
|
||||
notifyMessage(targetId, channel, data);
|
||||
|
||||
const lastVisible = container.find("div:visible").last();
|
||||
|
||||
if (data.msg.self
|
||||
|| lastVisible.hasClass("unread-marker")
|
||||
|| (lastVisible.hasClass("date-marker")
|
||||
@ -100,8 +102,10 @@ function processReceivedMessage(data) {
|
||||
|
||||
if ((data.msg.type === "message" || data.msg.type === "action") && channel.hasClass("channel")) {
|
||||
const nicks = channel.find(".users").data("nicks");
|
||||
|
||||
if (nicks) {
|
||||
const find = nicks.indexOf(data.msg.from.nick);
|
||||
|
||||
if (find !== -1) {
|
||||
nicks.splice(find, 1);
|
||||
nicks.unshift(data.msg.from.nick);
|
||||
@ -119,6 +123,7 @@ function notifyMessage(targetId, channel, msg) {
|
||||
}
|
||||
|
||||
const button = sidebar.find(".chan[data-id='" + targetId + "']");
|
||||
|
||||
if (msg.highlight || (options.notifyAllMessages && msg.type === "message")) {
|
||||
if (!document.hasFocus() || !channel.hasClass("active")) {
|
||||
if (options.notification) {
|
||||
@ -140,12 +145,15 @@ function notifyMessage(targetId, channel, msg) {
|
||||
body = msg.from.nick + " invited you to " + msg.channel;
|
||||
} else {
|
||||
title = msg.from.nick;
|
||||
|
||||
if (!button.hasClass("query")) {
|
||||
title += " (" + button.attr("aria-label").trim() + ")";
|
||||
}
|
||||
|
||||
if (msg.type === "message") {
|
||||
title += " says:";
|
||||
}
|
||||
|
||||
body = cleanIrcMessage(msg.text);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ socket.on("nick", function(data) {
|
||||
const id = data.network;
|
||||
const nick = data.nick;
|
||||
const network = sidebar.find("#network-" + id).data("nick", nick);
|
||||
|
||||
if (network.find(".active").length) {
|
||||
utils.setNick(nick);
|
||||
}
|
||||
|
@ -66,8 +66,10 @@ function expand() {
|
||||
|
||||
function join(args) {
|
||||
const channel = args[0];
|
||||
|
||||
if (channel) {
|
||||
const chan = findCurrentNetworkChan(channel);
|
||||
|
||||
if (chan.length) {
|
||||
chan.trigger("click");
|
||||
}
|
||||
@ -113,10 +115,12 @@ function confirmExit() {
|
||||
function move(array, old_index, new_index) {
|
||||
if (new_index >= array.length) {
|
||||
let k = new_index - array.length;
|
||||
|
||||
while ((k--) + 1) {
|
||||
this.push(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
array.splice(new_index, 0, array.splice(old_index, 1)[0]);
|
||||
return array;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ module.exports = requireViews.keys().reduce((acc, path) => {
|
||||
} else {
|
||||
tmp[key] = tmp[key] || {};
|
||||
}
|
||||
|
||||
tmp = tmp[key];
|
||||
});
|
||||
|
||||
|
1
index.js
1
index.js
@ -9,6 +9,7 @@ process.chdir(__dirname);
|
||||
// other issues
|
||||
// Try to display messages nicely, but gracefully degrade if anything goes wrong
|
||||
const pkg = require("./package.json");
|
||||
|
||||
if (!require("semver").satisfies(process.version, pkg.engines.node)) {
|
||||
let colors;
|
||||
let log;
|
||||
|
@ -397,6 +397,7 @@ function pullRequestNumbersInCommits(commits) {
|
||||
if (pullRequestId) {
|
||||
array.push(pullRequestId);
|
||||
}
|
||||
|
||||
return array;
|
||||
}, []);
|
||||
}
|
||||
@ -439,6 +440,7 @@ function printLine(entry) {
|
||||
if (entry.title) {
|
||||
return printPullRequest(entry);
|
||||
}
|
||||
|
||||
return printCommit(entry);
|
||||
}
|
||||
|
||||
@ -569,6 +571,7 @@ function parse(entries) {
|
||||
if (!result[dependencyType][packageName]) {
|
||||
result[dependencyType][packageName] = [];
|
||||
}
|
||||
|
||||
result[dependencyType][packageName].push(entry);
|
||||
} else {
|
||||
log.info(`${colors.bold(packageName)} was updated in ${colors.green("#" + entry.number)} then removed since last release. Skipping.`);
|
||||
@ -591,6 +594,7 @@ function parse(entries) {
|
||||
result.uncategorized.other.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {
|
||||
skipped: [],
|
||||
@ -616,6 +620,7 @@ function extractContributors(entries) {
|
||||
if (pullRequest.author.login !== "greenkeeper") {
|
||||
memo.add("@" + pullRequest.author.login);
|
||||
}
|
||||
|
||||
return memo;
|
||||
}, new Set());
|
||||
|
||||
@ -699,6 +704,7 @@ async function addToChangelog(newEntry) {
|
||||
} else {
|
||||
log.error(error);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -724,6 +730,7 @@ async function addToChangelog(newEntry) {
|
||||
|
||||
// Step 4: Print out some information about what just happened to the console
|
||||
const commitCommand = `git commit -m 'Add changelog entry for v${version}' CHANGELOG.md`;
|
||||
|
||||
if (isPrerelease(version)) {
|
||||
log.info(`You can now run: ${colors.bold(commitCommand)}`);
|
||||
} else {
|
||||
|
@ -115,14 +115,17 @@ Client.prototype.emit = function(event, data) {
|
||||
Client.prototype.find = function(channelId) {
|
||||
let network = null;
|
||||
let chan = null;
|
||||
|
||||
for (const i in this.networks) {
|
||||
const n = this.networks[i];
|
||||
chan = _.find(n.channels, {id: channelId});
|
||||
|
||||
if (chan) {
|
||||
network = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (network && chan) {
|
||||
return {
|
||||
network: network,
|
||||
@ -340,6 +343,7 @@ Client.prototype.input = function(data) {
|
||||
Client.prototype.inputLine = function(data) {
|
||||
const client = this;
|
||||
const target = client.find(data.target);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
@ -373,6 +377,7 @@ Client.prototype.inputLine = function(data) {
|
||||
|
||||
if (cmd in inputs) {
|
||||
const plugin = inputs[cmd];
|
||||
|
||||
if (connected || plugin.allowDisconnected) {
|
||||
connected = true;
|
||||
plugin.input.apply(client, [target.network, target.chan, cmd, args]);
|
||||
@ -427,6 +432,7 @@ Client.prototype.open = function(socketId, target) {
|
||||
}
|
||||
|
||||
target = this.find(target);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
@ -459,6 +465,7 @@ Client.prototype.sort = function(data) {
|
||||
|
||||
case "channels": {
|
||||
const network = _.find(this.networks, {id: data.target});
|
||||
|
||||
if (!network) {
|
||||
return;
|
||||
}
|
||||
@ -478,6 +485,7 @@ Client.prototype.sort = function(data) {
|
||||
Client.prototype.names = function(data) {
|
||||
const client = this;
|
||||
const target = client.find(data.target);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ ClientManager.prototype.autoloadUsers = function() {
|
||||
// Existing users removed since last time users were loaded
|
||||
_.difference(loaded, updatedUsers).forEach((name) => {
|
||||
const client = _.find(this.clients, {name: name});
|
||||
|
||||
if (client) {
|
||||
client.quit(true);
|
||||
this.clients = _.without(this.clients, client);
|
||||
@ -86,6 +87,7 @@ ClientManager.prototype.loadUser = function(name) {
|
||||
client = new Client(this, name, userConfig);
|
||||
this.clients.push(client);
|
||||
}
|
||||
|
||||
return client;
|
||||
};
|
||||
|
||||
@ -131,9 +133,11 @@ ClientManager.prototype.updateUser = function(name, opts, callback) {
|
||||
|
||||
if (!user) {
|
||||
log.error(`Tried to update invalid user ${colors.green(name)}. This is most likely a bug.`);
|
||||
|
||||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -151,9 +155,11 @@ ClientManager.prototype.updateUser = function(name, opts, callback) {
|
||||
return callback ? callback() : true;
|
||||
} catch (e) {
|
||||
log.error(`Failed to update user ${colors.green(name)} (${e})`);
|
||||
|
||||
if (callback) {
|
||||
callback(e);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
@ -40,9 +40,11 @@ _.merge(Helper.config, program.config);
|
||||
|
||||
require("./start");
|
||||
require("./config");
|
||||
|
||||
if (!Helper.config.public && !Helper.config.ldap.enable) {
|
||||
require("./users");
|
||||
}
|
||||
|
||||
require("./install");
|
||||
require("./uninstall");
|
||||
|
||||
|
@ -31,6 +31,7 @@ program
|
||||
}
|
||||
|
||||
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
|
||||
const errorHandler = (error) => {
|
||||
log.error(
|
||||
`Failed to uninstall ${colors.green(packageName)}. ` +
|
||||
|
@ -37,6 +37,7 @@ program
|
||||
log.error("Password cannot be empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
log.prompt({
|
||||
text: "Save logs to disk?",
|
||||
|
@ -28,6 +28,7 @@ program
|
||||
log.error(`User ${colors.bold(name)} does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const child_spawn = child.spawn(
|
||||
process.env.EDITOR || "vi",
|
||||
[Helper.getUserConfigPath(name)],
|
||||
|
@ -27,6 +27,7 @@ program
|
||||
log.error(`User ${colors.bold(name)} does not exist.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const file = Helper.getUserConfigPath(name);
|
||||
const user = require(file);
|
||||
log.prompt({
|
||||
@ -36,6 +37,7 @@ program
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
user.password = Helper.password.hash(password);
|
||||
user.sessions = {};
|
||||
fs.writeFileSync(
|
||||
|
@ -56,12 +56,15 @@ class Utils {
|
||||
} else if (/^\[.*\]$/.test(value)) { // Arrays
|
||||
// Supporting arrays `[a,b]` and `[a, b]`
|
||||
const array = value.slice(1, -1).split(/,\s*/);
|
||||
|
||||
// If [] is given, it will be parsed as `[ "" ]`, so treat this as empty
|
||||
if (array.length === 1 && array[0] === "") {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.map(parseValue); // Re-parses all values of the array
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
|
@ -53,10 +53,12 @@ function getVersion() {
|
||||
}
|
||||
|
||||
let _gitCommit;
|
||||
|
||||
function getGitCommit() {
|
||||
if (_gitCommit !== undefined) {
|
||||
return _gitCommit;
|
||||
}
|
||||
|
||||
try {
|
||||
_gitCommit = require("child_process")
|
||||
.execSync("git rev-parse --short HEAD 2> /dev/null") // Returns hash of current commit
|
||||
|
@ -141,11 +141,13 @@ Network.prototype.export = function() {
|
||||
})
|
||||
.map(function(chan) {
|
||||
const keys = ["name"];
|
||||
|
||||
if (chan.type === Chan.Type.CHANNEL) {
|
||||
keys.push("key");
|
||||
} else if (chan.type === Chan.Type.QUERY) {
|
||||
keys.push("type");
|
||||
}
|
||||
|
||||
return _.pick(chan, keys);
|
||||
});
|
||||
|
||||
|
@ -96,6 +96,7 @@ function advancedLdapAuth(user, password, callback) {
|
||||
});
|
||||
res.on("end", function() {
|
||||
ldapclient.unbind();
|
||||
|
||||
if (!found) {
|
||||
callback(false);
|
||||
}
|
||||
@ -115,15 +116,18 @@ function ldapAuth(manager, client, user, password, callback) {
|
||||
if (valid && !client) {
|
||||
manager.addUser(user, null);
|
||||
}
|
||||
|
||||
callback(valid);
|
||||
}
|
||||
|
||||
let auth;
|
||||
|
||||
if ("baseDN" in Helper.config.ldap) {
|
||||
auth = simpleLdapAuth;
|
||||
} else {
|
||||
auth = advancedLdapAuth;
|
||||
}
|
||||
|
||||
return auth(user, password, callbackWrapper);
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ function fetch(callback) {
|
||||
// Find the current release among releases on GitHub
|
||||
for (i = 0; i < body.length; i++) {
|
||||
release = body[i];
|
||||
|
||||
if (release.tag_name === versions.current.version) {
|
||||
versions.current.changelog = release.body_html;
|
||||
prerelease = release.prerelease;
|
||||
|
@ -19,6 +19,7 @@ exports.input = function(network, chan, cmd, args) {
|
||||
|
||||
if (!network.irc.network.cap.isEnabled("echo-message")) {
|
||||
const channel = network.getChannel(target);
|
||||
|
||||
if (typeof channel !== "undefined") {
|
||||
network.irc.emit("privmsg", {
|
||||
nick: network.irc.user.nick,
|
||||
|
@ -8,6 +8,7 @@ exports.commands = ["query"];
|
||||
|
||||
exports.input = function(network, chan, cmd, args) {
|
||||
const target = args[0];
|
||||
|
||||
if (args.length === 0 || target.length === 0) {
|
||||
chan.pushMessage(this, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
@ -17,11 +18,13 @@ exports.input = function(network, chan, cmd, args) {
|
||||
}
|
||||
|
||||
const query = _.find(network.channels, {name: target});
|
||||
|
||||
if (typeof query !== "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
const char = target[0];
|
||||
|
||||
if (network.irc.network.options.CHANTYPES && network.irc.network.options.CHANTYPES.includes(char)) {
|
||||
chan.pushMessage(this, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
|
@ -14,6 +14,7 @@ exports.input = function({irc}, chan, cmd, args) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
irc.setTopic(chan.name, args.join(" "));
|
||||
return true;
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ module.exports = function(irc, network) {
|
||||
irc.on("banlist", function(banlist) {
|
||||
const channel = banlist.channel;
|
||||
const bans = banlist.bans;
|
||||
|
||||
if (!bans || bans.length === 0) {
|
||||
const msg = new Msg({
|
||||
time: Date.now(),
|
||||
@ -21,6 +22,7 @@ module.exports = function(irc, network) {
|
||||
|
||||
const chanName = `Banlist for ${channel}`;
|
||||
let chan = network.getChannel(chanName);
|
||||
|
||||
if (typeof chan === "undefined") {
|
||||
chan = new Chan({
|
||||
type: Chan.Type.SPECIAL,
|
||||
|
@ -122,6 +122,7 @@ function parse(msg, preview, res, client) {
|
||||
if (!preview.link.startsWith("https://")) {
|
||||
break;
|
||||
}
|
||||
|
||||
preview.type = "audio";
|
||||
preview.res = res.type;
|
||||
|
||||
@ -133,6 +134,7 @@ function parse(msg, preview, res, client) {
|
||||
if (!preview.link.startsWith("https://")) {
|
||||
break;
|
||||
}
|
||||
|
||||
preview.res = res.type;
|
||||
preview.type = "video";
|
||||
|
||||
@ -191,6 +193,7 @@ function emitPreview(client, msg, preview) {
|
||||
|
||||
function fetch(uri, cb) {
|
||||
let req;
|
||||
|
||||
try {
|
||||
req = request.get({
|
||||
url: uri,
|
||||
@ -214,6 +217,7 @@ function fetch(uri, cb) {
|
||||
// response is an image
|
||||
// if Content-Length header reports a size exceeding the prefetch limit, abort fetch
|
||||
const contentLength = parseInt(res.headers["content-length"], 10) || 0;
|
||||
|
||||
if (contentLength > limit) {
|
||||
req.abort();
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ module.exports = function(irc, network) {
|
||||
}
|
||||
|
||||
let match;
|
||||
|
||||
while ((match = nickRegExp.exec(data.message))) {
|
||||
if (chan.findUser(match[1])) {
|
||||
msg.users.push(match[1]);
|
||||
|
@ -16,6 +16,7 @@ module.exports = function(irc, network) {
|
||||
}
|
||||
|
||||
const targetChan = network.getChannel(data.channel);
|
||||
|
||||
if (typeof targetChan === "undefined") {
|
||||
return;
|
||||
}
|
||||
@ -39,6 +40,7 @@ module.exports = function(irc, network) {
|
||||
targetChan = network.channels[0];
|
||||
} else {
|
||||
targetChan = network.getChannel(data.target);
|
||||
|
||||
if (typeof targetChan === "undefined") {
|
||||
return;
|
||||
}
|
||||
@ -80,6 +82,7 @@ module.exports = function(irc, network) {
|
||||
}
|
||||
|
||||
const user = targetChan.findUser(mode.param);
|
||||
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ module.exports = function(irc, network) {
|
||||
|
||||
irc.on("userlist", function(data) {
|
||||
const chan = network.getChannel(data.channel);
|
||||
|
||||
if (typeof chan === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ module.exports = function(irc, network) {
|
||||
}
|
||||
|
||||
let msg;
|
||||
|
||||
if (data.error) {
|
||||
msg = new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
|
@ -18,6 +18,7 @@ function loadLocalThemes() {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
builtInThemes
|
||||
.filter((theme) => theme.endsWith(".css"))
|
||||
.map(makeLocalThemeObject)
|
||||
@ -27,6 +28,7 @@ function loadLocalThemes() {
|
||||
|
||||
function addTheme(packageName, packageObject) {
|
||||
const theme = makePackageThemeObject(packageName, packageObject);
|
||||
|
||||
if (theme) {
|
||||
themes.set(theme.name, theme);
|
||||
}
|
||||
@ -54,6 +56,7 @@ function makePackageThemeObject(moduleName, module) {
|
||||
if (!module || module.type !== "theme") {
|
||||
return;
|
||||
}
|
||||
|
||||
const modulePath = Helper.getPackageModulePath(moduleName);
|
||||
const displayName = module.name || moduleName;
|
||||
const filename = path.join(modulePath, module.css);
|
||||
|
@ -55,9 +55,11 @@ module.exports = function() {
|
||||
app.get("/themes/:theme.css", (req, res) => {
|
||||
const themeName = req.params.theme;
|
||||
const theme = themes.getFilename(themeName);
|
||||
|
||||
if (theme === undefined) {
|
||||
return res.status(404).send("Not found");
|
||||
}
|
||||
|
||||
return res.sendFile(theme);
|
||||
});
|
||||
|
||||
@ -65,9 +67,11 @@ module.exports = function() {
|
||||
const packageName = req.params.package;
|
||||
const fileName = req.params.filename;
|
||||
const packageFile = packages.getPackage(packageName);
|
||||
|
||||
if (!packageFile || !packages.getStylesheets().includes(`${packageName}/${fileName}`)) {
|
||||
return res.status(404).send("Not found");
|
||||
}
|
||||
|
||||
const packagePath = Helper.getPackageModulePath(packageName);
|
||||
return res.sendFile(path.join(packagePath, fileName));
|
||||
});
|
||||
@ -161,6 +165,7 @@ module.exports = function() {
|
||||
|
||||
// Handle ctrl+c and kill gracefully
|
||||
let suicideTimeout = null;
|
||||
|
||||
const exitGracefully = function() {
|
||||
if (suicideTimeout !== null) {
|
||||
return;
|
||||
@ -304,12 +309,14 @@ function initializeClient(socket, client, token, lastMessage) {
|
||||
const old = data.old_password;
|
||||
const p1 = data.new_password;
|
||||
const p2 = data.verify_password;
|
||||
|
||||
if (typeof p1 === "undefined" || p1 === "") {
|
||||
socket.emit("change-password", {
|
||||
error: "Please enter a new password",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (p1 !== p2) {
|
||||
socket.emit("change-password", {
|
||||
error: "Both new password fields must match",
|
||||
@ -326,6 +333,7 @@ function initializeClient(socket, client, token, lastMessage) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = Helper.password.hash(p1);
|
||||
|
||||
client.setPassword(hash, (success) => {
|
||||
@ -375,6 +383,7 @@ function initializeClient(socket, client, token, lastMessage) {
|
||||
|
||||
socket.on("msg:preview:toggle", function(data) {
|
||||
const networkAndChan = client.find(data.target);
|
||||
|
||||
if (!networkAndChan) {
|
||||
return;
|
||||
}
|
||||
@ -602,12 +611,14 @@ function performAuthentication(data) {
|
||||
let auth = () => {
|
||||
log.error("None of the auth plugins is enabled");
|
||||
};
|
||||
|
||||
for (let i = 0; i < authPlugins.length; ++i) {
|
||||
if (authPlugins[i].isEnabled()) {
|
||||
auth = authPlugins[i].auth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auth(manager, client, data.user, data.password, authCallback);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ module.exports.write = function(user, network, chan, msg) {
|
||||
let line = `[${time}] `;
|
||||
|
||||
const type = msg.type.trim();
|
||||
|
||||
if (type === "message" || type === "highlight") {
|
||||
// Format:
|
||||
// [2014-01-01 00:00:00] <Arnold> Put that cookie down.. Now!!
|
||||
|
@ -116,6 +116,7 @@ describe("LDAP authentication plugin", function() {
|
||||
|
||||
before(function(done) {
|
||||
originalLogInfo = log.info;
|
||||
|
||||
log.info = () => {};
|
||||
|
||||
server = startLdapServer(done);
|
||||
|
@ -10,6 +10,7 @@ describe("packages", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
originalLogInfo = log.info;
|
||||
|
||||
log.info = () => {};
|
||||
|
||||
delete require.cache[require.resolve("../../../src/plugins/packages")];
|
||||
|
@ -12,6 +12,7 @@ describe("Server", function() {
|
||||
|
||||
before(function() {
|
||||
originalLogInfo = log.info;
|
||||
|
||||
log.info = () => {};
|
||||
|
||||
server = require("../src/server")();
|
||||
|
@ -10,6 +10,7 @@ const Chan = require("../src/models/chan");
|
||||
function MockClient() {
|
||||
this.user = {nick: "test-user"};
|
||||
}
|
||||
|
||||
util.inherits(MockClient, EventEmitter);
|
||||
|
||||
MockClient.prototype.createMessage = function(opts) {
|
||||
|
Loading…
Reference in New Issue
Block a user