From 4ec10b922aaff90592b88deb8e6c5fcec07b33e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Wed, 29 Nov 2017 01:22:03 -0500 Subject: [PATCH] Clone instances of `User` in `Msg` to avoid unintentional mutations --- client/views/actions/invite.tpl | 2 +- src/models/msg.js | 12 ++++++++++++ src/plugins/irc-events/invite.js | 2 +- test/models/msg.js | 19 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/client/views/actions/invite.tpl b/client/views/actions/invite.tpl index 93215852..84146f2a 100644 --- a/client/views/actions/invite.tpl +++ b/client/views/actions/invite.tpl @@ -3,7 +3,7 @@ invited {{#if invitedYou}} you {{else}} - {{> ../user_name invited}} + {{> ../user_name target}} {{/if}} to {{{parse channel}}} diff --git a/src/models/msg.js b/src/models/msg.js index c48de927..0d12162b 100644 --- a/src/models/msg.js +++ b/src/models/msg.js @@ -6,6 +6,18 @@ var id = 0; class Msg { constructor(attr) { + // Some properties need to be copied in the Msg object instead of referenced + if (attr) { + ["from", "target"].forEach((prop) => { + if (attr[prop]) { + this[prop] = { + mode: attr[prop].mode, + nick: attr[prop].nick, + }; + } + }); + } + _.defaults(this, attr, { from: "", id: id++, diff --git a/src/plugins/irc-events/invite.js b/src/plugins/irc-events/invite.js index 761bbcfd..1ce3c3e1 100644 --- a/src/plugins/irc-events/invite.js +++ b/src/plugins/irc-events/invite.js @@ -16,7 +16,7 @@ module.exports = function(irc, network) { type: Msg.Type.INVITE, time: data.time, from: chan.getUser(data.nick), - invited: chan.getUser(data.invited), + target: chan.getUser(data.invited), channel: data.channel, highlight: true, invitedYou: data.invited === irc.user.nick, diff --git a/test/models/msg.js b/test/models/msg.js index 20c202da..bce3ea92 100644 --- a/test/models/msg.js +++ b/test/models/msg.js @@ -3,8 +3,27 @@ const expect = require("chai").expect; const Msg = require("../../src/models/msg"); +const User = require("../../src/models/user"); describe("Msg", function() { + ["from", "target"].forEach((prop) => { + it(`should keep a copy of the original user in the \`${prop}\` property`, function() { + const prefixLookup = {a: "&", o: "@"}; + const user = new User({ + modes: ["o"], + nick: "foo", + }, prefixLookup); + const msg = new Msg({[prop]: user}); + + // Mutating the user + user.setModes(["a"], prefixLookup); + user.nick = "bar"; + + // Message's `.from`/etc. should still refer to the original user + expect(msg[prop]).to.deep.equal({mode: "@", nick: "foo"}); + }); + }); + describe("#findPreview(link)", function() { const msg = new Msg({ previews: [{