Move custom highlights to the server

This commit is contained in:
Pavel Djundik 2019-01-16 11:23:12 +02:00
parent 40bf9ee8ba
commit b066dc301e
6 changed files with 55 additions and 63 deletions

View File

@ -1,7 +1,6 @@
"use strict"; "use strict";
const $ = require("jquery"); const $ = require("jquery");
const escapeRegExp = require("lodash/escapeRegExp");
const storage = require("./localStorage"); const storage = require("./localStorage");
const socket = require("./socket"); const socket = require("./socket");
const {vueApp} = require("./vue"); const {vueApp} = require("./vue");
@ -27,9 +26,11 @@ const settings = vueApp.settings;
const noSync = ["syncSettings"]; const noSync = ["syncSettings"];
// alwaysSync is reserved for things like "highlights". // alwaysSync is reserved for settings that should be synced
// TODO: figure out how to deal with legacy clients that have different settings. // to the server regardless of the clients sync setting.
const alwaysSync = []; const alwaysSync = [
"highlights",
];
// Process usersettings from localstorage. // Process usersettings from localstorage.
let userSettings = JSON.parse(storage.get("settings")) || false; let userSettings = JSON.parse(storage.get("settings")) || false;
@ -39,7 +40,13 @@ if (!userSettings) {
settings.syncSettings = true; settings.syncSettings = true;
} else { } else {
for (const key in settings) { for (const key in settings) {
if (userSettings[key] !== undefined) { // Older The Lounge versions converted highlights to an array, turn it back into a string
if (key === "highlights" && typeof userSettings[key] === "object") {
userSettings[key] = userSettings[key].join(", ");
}
// Make sure the setting in local storage has the same type that the code expects
if (typeof userSettings[key] !== "undefined" && typeof settings[key] === typeof userSettings[key]) {
settings[key] = userSettings[key]; settings[key] = userSettings[key];
} }
} }
@ -62,7 +69,6 @@ module.exports = {
alwaysSync, alwaysSync,
noSync, noSync,
initialized: false, initialized: false,
highlightsRE: null,
settings, settings,
syncAllSettings, syncAllSettings,
processSetting, processSetting,
@ -92,32 +98,6 @@ function applySetting(name, value) {
} }
} else if (name === "userStyles" && !noCSSparamReg.test(window.location.search)) { } else if (name === "userStyles" && !noCSSparamReg.test(window.location.search)) {
$userStyles.html(value); $userStyles.html(value);
} else if (name === "highlights") {
let highlights;
if (typeof value === "string") {
highlights = value.split(",").map(function(h) {
return h.trim();
});
} else {
highlights = value;
}
highlights = highlights.filter(function(h) {
// Ensure we don't have empty string in the list of highlights
// otherwise, users get notifications for everything
return h !== "";
});
// Construct regex with wordboundary for every highlight item
const highlightsTokens = highlights.map(function(h) {
return escapeRegExp(h);
});
if (highlightsTokens && highlightsTokens.length) {
module.exports.highlightsRE = new RegExp(`(?:^| |\t)(?:${highlightsTokens.join("|")})(?:\t| |$)`, "i");
} else {
module.exports.highlightsRE = null;
}
} else if (name === "desktopNotifications") { } else if (name === "desktopNotifications") {
if (("Notification" in window) && value && Notification.permission !== "granted") { if (("Notification" in window) && value && Notification.permission !== "granted") {
Notification.requestPermission(updateDesktopNotificationStatus); Notification.requestPermission(updateDesktopNotificationStatus);
@ -135,25 +115,11 @@ function settingSetEmit(name, value) {
// When sync is `true` the setting will also be send to the backend for syncing. // When sync is `true` the setting will also be send to the backend for syncing.
function updateSetting(name, value, sync) { function updateSetting(name, value, sync) {
let storeValue = value;
// First convert highlights if input is a string.
// Otherwise we are comparing the wrong types.
if (name === "highlights" && typeof value === "string") {
storeValue = value.split(",").map(function(h) {
return h.trim();
}).filter(function(h) {
// Ensure we don't have empty string in the list of highlights
// otherwise, users get notifications for everything
return h !== "";
});
}
const currentOption = settings[name]; const currentOption = settings[name];
// Only update and process when the setting is actually changed. // Only update and process when the setting is actually changed.
if (currentOption !== storeValue) { if (currentOption !== value) {
settings[name] = storeValue; settings[name] = value;
storage.set("settings", JSON.stringify(settings)); storage.set("settings", JSON.stringify(settings));
applySetting(name, value); applySetting(name, value);

View File

@ -49,15 +49,6 @@ socket.on("msg", function(data) {
} }
} }
// See if any of the custom highlight regexes match
// TODO: This needs to be done on the server side with settings sync
if (!data.msg.highlight && !data.msg.self
&& (data.msg.type === "message" || data.msg.type === "notice")
&& options.highlightsRE
&& options.highlightsRE.exec(data.msg.text)) {
data.msg.highlight = true;
}
channel.messages.push(data.msg); channel.messages.push(data.msg);
if (data.msg.self) { if (data.msg.self) {

View File

@ -31,7 +31,7 @@ const vueApp = new Vue({
nickPostfix: "", nickPostfix: "",
coloredNicks: true, coloredNicks: true,
desktopNotifications: false, desktopNotifications: false,
highlights: [], highlights: "",
links: true, links: true,
motd: true, motd: true,
notification: true, notification: true,

View File

@ -10,6 +10,7 @@ const Network = require("./models/network");
const Helper = require("./helper"); const Helper = require("./helper");
const UAParser = require("ua-parser-js"); const UAParser = require("ua-parser-js");
const uuidv4 = require("uuid/v4"); const uuidv4 = require("uuid/v4");
const escapeRegExp = require("lodash/escapeRegExp");
const MessageStorage = require("./plugins/messageStorage/sqlite"); const MessageStorage = require("./plugins/messageStorage/sqlite");
const TextFileMessageStorage = require("./plugins/messageStorage/text"); const TextFileMessageStorage = require("./plugins/messageStorage/text");
@ -81,6 +82,7 @@ function Client(manager, name, config = {}) {
sockets: manager.sockets, sockets: manager.sockets,
manager: manager, manager: manager,
messageStorage: [], messageStorage: [],
highlightRegex: null,
}); });
const client = this; const client = this;
@ -111,6 +113,12 @@ function Client(manager, name, config = {}) {
client.config.sessions = {}; client.config.sessions = {};
} }
if (typeof client.config.clientSettings !== "object") {
client.config.clientSettings = {};
}
client.compileCustomHighlights();
_.forOwn(client.config.sessions, (session) => { _.forOwn(client.config.sessions, (session) => {
if (session.pushSubscription) { if (session.pushSubscription) {
this.registerPushSubscription(session, session.pushSubscription, true); this.registerPushSubscription(session, session.pushSubscription, true);
@ -373,6 +381,29 @@ Client.prototype.inputLine = function(data) {
} }
}; };
Client.prototype.compileCustomHighlights = function() {
const client = this;
if (typeof client.config.clientSettings.highlights !== "string") {
client.highlightRegex = null;
return;
}
// Ensure we don't have empty string in the list of highlights
// otherwise, users get notifications for everything
const highlightsTokens = client.config.clientSettings.highlights
.split(",")
.map((highlight) => escapeRegExp(highlight.trim()))
.filter((highlight) => highlight.length > 0);
if (highlightsTokens.length === 0) {
client.highlightRegex = null;
return;
}
client.highlightRegex = new RegExp(`(?:^| |\t)(?:${highlightsTokens.join("|")})(?:\t| |$)`, "i");
};
Client.prototype.more = function(data) { Client.prototype.more = function(data) {
const client = this; const client = this;
const target = client.find(data.target); const target = client.find(data.target);

View File

@ -117,6 +117,11 @@ module.exports = function(irc, network) {
// Non-self messages are highlighted as soon as the nick is detected // Non-self messages are highlighted as soon as the nick is detected
if (!msg.highlight && !msg.self) { if (!msg.highlight && !msg.self) {
msg.highlight = network.highlightRegex.test(data.message); msg.highlight = network.highlightRegex.test(data.message);
// If we still don't have a highlight, test against custom highlights if there's any
if (!msg.highlight && client.highlightRegex) {
msg.highlight = client.highlightRegex.test(data.message);
}
} }
let match; let match;

View File

@ -498,11 +498,6 @@ function initializeClient(socket, client, token, lastMessage) {
return; return;
} }
// Older user configs will not have the clientSettings property.
if (!client.config.hasOwnProperty("clientSettings")) {
client.config.clientSettings = {};
}
// We do not need to do write operations and emit events if nothing changed. // We do not need to do write operations and emit events if nothing changed.
if (client.config.clientSettings[newSetting.name] !== newSetting.value) { if (client.config.clientSettings[newSetting.name] !== newSetting.value) {
client.config.clientSettings[newSetting.name] = newSetting.value; client.config.clientSettings[newSetting.name] = newSetting.value;
@ -516,6 +511,10 @@ function initializeClient(socket, client, token, lastMessage) {
client.manager.updateUser(client.name, { client.manager.updateUser(client.name, {
clientSettings: client.config.clientSettings, clientSettings: client.config.clientSettings,
}); });
if (newSetting.name === "highlights") {
client.compileCustomHighlights();
}
} }
}); });