瀏覽代碼

Check for support before allowing message moderation

JC Brand 5 年之前
父節點
當前提交
025cdbf18f
共有 6 個文件被更改,包括 74 次插入26 次删除
  1. 46 10
      spec/retractions.js
  2. 7 3
      src/converse-message-view.js
  3. 5 0
      src/headless/converse-muc.js
  4. 1 2
      src/templates/message.html
  5. 14 0
      tests/mock.js
  6. 1 11
      tests/utils.js

+ 46 - 10
spec/retractions.js

@@ -48,7 +48,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
 
 
                 const received_stanza = u.toStanza(`
                 const received_stanza = u.toStanza(`
                     <message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
                     <message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
@@ -92,7 +93,8 @@
 
 
                 const date = (new Date()).toISOString();
                 const date = (new Date()).toISOString();
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
 
 
                 const retraction_stanza = u.toStanza(`
                 const retraction_stanza = u.toStanza(`
                     <message type="groupchat" id='retraction-id-1' from="${muc_jid}/eve" to="${muc_jid}/romeo">
                     <message type="groupchat" id='retraction-id-1' from="${muc_jid}/eve" to="${muc_jid}/romeo">
@@ -321,7 +323,8 @@
                         async function (done, _converse) {
                         async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
 
 
                 const received_stanza = u.toStanza(`
                 const received_stanza = u.toStanza(`
                     <message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
                     <message to='${_converse.jid}' from='${muc_jid}/eve' type='groupchat' id='${_converse.connection.getUniqueId()}'>
@@ -363,7 +366,9 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
+
                 const view = _converse.api.chatviews.get(muc_jid);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const occupant = view.model.getOwnOccupant();
                 const occupant = view.model.getOwnOccupant();
                 expect(occupant.get('role')).toBe('moderator');
                 expect(occupant.get('role')).toBe('moderator');
@@ -439,6 +444,31 @@
                 done();
                 done();
             }));
             }));
 
 
+            it("can not be retracted if the MUC doesn't support message moderation",
+                mock.initConverse(
+                    ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+                    async function (done, _converse) {
+
+                const muc_jid = 'lounge@montague.lit';
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const view = _converse.api.chatviews.get(muc_jid);
+                const occupant = view.model.getOwnOccupant();
+                expect(occupant.get('role')).toBe('moderator');
+
+                const received_stanza = u.toStanza(`
+                    <message to='${_converse.jid}' from='${muc_jid}/mallory' type='groupchat' id='${_converse.connection.getUniqueId()}'>
+                        <body>Visit this site to get free Bitcoin!</body>
+                        <stanza-id xmlns='urn:xmpp:sid:0' id='stanza-id-1' by='${muc_jid}'/>
+                    </message>
+                `);
+                await view.model.onMessage(received_stanza);
+                await u.waitUntil(() => view.el.querySelector('.chat-msg__content'));
+                expect(view.el.querySelector('.chat-msg__content .chat-msg__action-retract')).toBe(null);
+                const result = await view.model.canRetractMessages();
+                expect(result).toBe(false);
+                done();
+            }));
+
 
 
             it("can be retracted by a moderator, with the retraction message received before the IQ response",
             it("can be retracted by a moderator, with the retraction message received before the IQ response",
                 mock.initConverse(
                 mock.initConverse(
@@ -446,7 +476,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const occupant = view.model.getOwnOccupant();
                 const occupant = view.model.getOwnOccupant();
                 expect(occupant.get('role')).toBe('moderator');
                 expect(occupant.get('role')).toBe('moderator');
@@ -514,7 +545,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const occupant = view.model.getOwnOccupant();
                 const occupant = view.model.getOwnOccupant();
                 expect(occupant.get('role')).toBe('moderator');
                 expect(occupant.get('role')).toBe('moderator');
@@ -565,7 +597,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const occupant = view.model.getOwnOccupant();
                 const occupant = view.model.getOwnOccupant();
                 expect(occupant.get('role')).toBe('moderator');
                 expect(occupant.get('role')).toBe('moderator');
@@ -615,7 +648,8 @@
                 _converse.STANZA_TIMEOUT = 1;
                 _converse.STANZA_TIMEOUT = 1;
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const view = _converse.api.chatviews.get(muc_jid);
                 const occupant = view.model.getOwnOccupant();
                 const occupant = view.model.getOwnOccupant();
                 expect(occupant.get('role')).toBe('moderator');
                 expect(occupant.get('role')).toBe('moderator');
@@ -740,7 +774,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.chatboxviews.get(muc_jid);
                 const view = _converse.chatboxviews.get(muc_jid);
 
 
                 const sent_IQs = _converse.connection.IQ_stanzas;
                 const sent_IQs = _converse.connection.IQ_stanzas;
@@ -816,7 +851,8 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
-                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+                const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+                await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
                 const view = _converse.chatboxviews.get(muc_jid);
                 const view = _converse.chatboxviews.get(muc_jid);
 
 
                 const sent_IQs = _converse.connection.IQ_stanzas;
                 const sent_IQs = _converse.connection.IQ_stanzas;

+ 7 - 3
src/converse-message-view.js

@@ -242,15 +242,19 @@ converse.plugins.add('converse-message-view', {
                 const role = this.model.vcard ? this.model.vcard.get('role') : null;
                 const role = this.model.vcard ? this.model.vcard.get('role') : null;
                 const roles = role ? role.split(',') : [];
                 const roles = role ? role.split(',') : [];
                 const is_retracted = this.model.get('retracted') || this.model.get('moderated') === 'retracted';
                 const is_retracted = this.model.get('retracted') || this.model.get('moderated') === 'retracted';
-
+                const is_groupchat_message = this.model.get('type') === 'groupchat';
+                const is_own_message = this.model.get('sender') === 'me';
+                const chatbox = this.model.collection.chatbox;
+                const retractable= is_groupchat_message ? await chatbox.canRetractMessages() : is_own_message;
                 const msg = u.stringToElement(tpl_message(
                 const msg = u.stringToElement(tpl_message(
                     Object.assign(
                     Object.assign(
                         this.model.toJSON(), {
                         this.model.toJSON(), {
                          __,
                          __,
+                        is_groupchat_message,
                         is_retracted,
                         is_retracted,
-                        'extra_classes': this.getExtraMessageClasses(),
-                        'is_groupchat_message': this.model.get('type') === 'groupchat',
+                        retractable,
                         'is_me_message': this.model.isMeCommand(),
                         'is_me_message': this.model.isMeCommand(),
+                        'extra_classes': this.getExtraMessageClasses(),
                         'label_show': __('Show more'),
                         'label_show': __('Show more'),
                         'occupant': this.model.occupant,
                         'occupant': this.model.occupant,
                         'pretty_time': time.format(_converse.time_format),
                         'pretty_time': time.format(_converse.time_format),

+ 5 - 0
src/headless/converse-muc.js

@@ -707,6 +707,11 @@ converse.plugins.add('converse-muc', {
                 return _converse.ChatBox.prototype.close.call(this);
                 return _converse.ChatBox.prototype.close.call(this);
             },
             },
 
 
+            canRetractMessages () {
+                const self = this.getOwnOccupant();
+                return self && self.isModerator() && _converse.api.disco.supports(Strophe.NS.MODERATE, this.get('jid'));
+            },
+
             sendUnavailablePresence (exit_msg) {
             sendUnavailablePresence (exit_msg) {
                 const presence = $pres({
                 const presence = $pres({
                     type: "unavailable",
                     type: "unavailable",

+ 1 - 2
src/templates/message.html

@@ -41,8 +41,7 @@
                 {[ if (o.editable) { ]}
                 {[ if (o.editable) { ]}
                     <button class="chat-msg__action chat-msg__action-edit fa fa-pencil-alt" title="{{{o.__('Edit this message')}}}"></button>
                     <button class="chat-msg__action chat-msg__action-edit fa fa-pencil-alt" title="{{{o.__('Edit this message')}}}"></button>
                 {[ } ]}
                 {[ } ]}
-                <!-- FIXME -->
-                {[ if ((o.sender === 'me' || o.is_groupchat_message) && true) { ]}
+                {[ if (o.retractable) { ]}
                     <button class="chat-msg__action chat-msg__action-retract fa fa-trash-alt" title="{{{o.__('Retract this message')}}}"></button>
                     <button class="chat-msg__action chat-msg__action-retract fa fa-trash-alt" title="{{{o.__('Retract this message')}}}"></button>
                 {[ } ]}
                 {[ } ]}
             </div>
             </div>

+ 14 - 0
tests/mock.js

@@ -69,6 +69,20 @@
     };
     };
 
 
     const mock = {};
     const mock = {};
+
+    mock.default_muc_features = [
+        'http://jabber.org/protocol/muc',
+        'jabber:iq:register',
+        Strophe.NS.SID,
+        Strophe.NS.MAM,
+        'muc_passwordprotected',
+        'muc_hidden',
+        'muc_temporary',
+        'muc_open',
+        'muc_unmoderated',
+        'muc_anonymous'
+    ];
+
     mock.view_mode = 'overlayed';
     mock.view_mode = 'overlayed';
 
 
     // Names from http://www.fakenamegenerator.com/
     // Names from http://www.fakenamegenerator.com/

+ 1 - 11
tests/utils.js

@@ -167,17 +167,7 @@
                 'type': 'text'
                 'type': 'text'
             }).up();
             }).up();
 
 
-        features = features.length ? features : [
-            'http://jabber.org/protocol/muc',
-            'jabber:iq:register',
-            Strophe.NS.SID,
-            Strophe.NS.MAM,
-            'muc_passwordprotected',
-            'muc_hidden',
-            'muc_temporary',
-            'muc_open',
-            'muc_unmoderated',
-            'muc_anonymous']
+        features = features.length ? features : mock.default_muc_features;
         features.forEach(f => features_stanza.c('feature', {'var': f}).up());
         features.forEach(f => features_stanza.c('feature', {'var': f}).up());
         features_stanza.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
         features_stanza.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
             .c('field', {'var':'FORM_TYPE', 'type':'hidden'})
             .c('field', {'var':'FORM_TYPE', 'type':'hidden'})