Ariel Fuggini 4 anni fa
parent
commit
2ab5a1c779

+ 53 - 0
spec/muc_messages.js

@@ -702,4 +702,57 @@ describe("A Groupchat Message", function () {
         expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
         expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
         done();
         done();
     }));
     }));
+
+    it("can mute user",
+        mock.initConverse(
+            ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+            async function (done, _converse) {
+
+        const muc_jid = 'lounge@montague.lit';
+        const features = [...mock.default_muc_features, Strophe.NS.MODERATE];
+        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', features);
+
+        const view = _converse.api.chatviews.get(muc_jid);
+
+        for (let i = 0; i < 5; i++) {
+            const message_stanza = u.toStanza(`
+                <message to='${_converse.jid}' from='${muc_jid}/mallory' type='groupchat' id='${_converse.connection.getUniqueId()}'>
+                    <body>Message ${i}</body>
+                    <stanza-id xmlns='urn:xmpp:sid:0' id='stanza-id-0${i}' by='${muc_jid}'/>
+                </message>
+            `);
+            await view.model.handleMessageStanza(message_stanza);
+        }
+        await u.waitUntil(() => view.model.messages.length === 5);
+        
+        // Mute option is present
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-content__messages .message.chat-msg').length === 5);
+        const mute_buttons = view.el.querySelectorAll('.chat-msg__actions .chat-msg__action-mute');
+        expect(mute_buttons.length).toBe(5);
+        
+        // Stanza is sent
+        mute_buttons[0].click();
+        
+        const IQ_stanzas = _converse.connection.IQ_stanzas;
+        await u.waitUntil(() => IQ_stanzas.length);
+        
+        const [block_stanza] = IQ_stanzas.filter(s => sizzle('block', s).length);
+        
+        expect(block_stanza).not.toBe(undefined);
+        expect(Strophe.serialize(block_stanza)).toBe(`<iq from="romeo@montague.lit/orchard" id="${block_stanza.attributes.id?.value}" type="set" xmlns="jabber:client"><block xmlns="urn:xmpp:blocking"><item jid="lounge@montague.lit/mallory"/></block></iq>`);
+        
+        const iq_response_stanza = u.toStanza(`
+            <iq id="${block_stanza.attributes.id?.value}" type="result" to="romeo@montague.lit/orchard"/>
+        `);
+        
+        _converse.connection._dataRecv(mock.createRequest(iq_response_stanza));
+        
+        // Model is destroyed
+        await u.waitUntil(() => view.model.messages.length === 0);
+
+        // UI is removed
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-content__messages .message.chat-msg').length === 0);
+        
+        done();
+    }));
 });
 });

+ 15 - 0
src/components/message-actions.js

@@ -44,8 +44,23 @@ class MessageActions extends CustomElement {
         this.chatview.onMessageRetractButtonClicked(this.model);
         this.chatview.onMessageRetractButtonClicked(this.model);
     }
     }
 
 
+    onMuteUserButtonClicked (ev) {
+        ev.preventDefault();
+        this.chatview.model.onMuteUser(this.model);
+    }
+
     async renderActions () {
     async renderActions () {
         const buttons = [];
         const buttons = [];
+        if (this.model.get('sender') !== 'me') {
+            buttons.push({
+                'i18n_text': __('Mute User'),
+                'handler': ev => this.onMuteUserButtonClicked(ev),
+                'button_class': 'chat-msg__action-mute',
+                'icon_class': 'fa fa-comment-slash',
+                'name': 'mute'
+            });
+        }
+
         if (this.editable) {
         if (this.editable) {
             buttons.push({
             buttons.push({
                 'i18n_text': this.correcting ? __('Cancel Editing') : __('Edit'),
                 'i18n_text': this.correcting ? __('Cancel Editing') : __('Edit'),

+ 12 - 0
src/converse-muc-views.js

@@ -564,6 +564,15 @@ export const ChatRoomView = ChatBoxView.extend({
             'name': 'details'
             'name': 'details'
         });
         });
 
 
+        buttons.push({
+            'i18n_text': __('Muted users list'),
+            'i18n_title': __('See muted users'),
+            'handler': ev => this.listMutedUsers(ev),
+            'a_class': 'configure-chatroom-button',
+            'icon_class': 'fa-wrench',
+            'name': 'configure'
+        });
+
         if (this.model.getOwnAffiliation() === 'owner') {
         if (this.model.getOwnAffiliation() === 'owner') {
             buttons.push({
             buttons.push({
                 'i18n_text': __('Configure'),
                 'i18n_text': __('Configure'),
@@ -679,6 +688,9 @@ export const ChatRoomView = ChatBoxView.extend({
         this.muc_invite_modal.show(ev);
         this.muc_invite_modal.show(ev);
     },
     },
 
 
+    listMutedUsers (ev) {
+        this.model.listMutedUsers();
+    },
 
 
     /**
     /**
      * Callback method that gets called after the chat has become visible.
      * Callback method that gets called after the chat has become visible.

+ 1 - 0
src/headless/converse-core.js

@@ -28,6 +28,7 @@ import { sprintf } from 'sprintf-js';
 dayjs.extend(advancedFormat);
 dayjs.extend(advancedFormat);
 
 
 // Add Strophe Namespaces
 // Add Strophe Namespaces
+Strophe.addNamespace('BLOCKING', 'urn:xmpp:blocking');
 Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2');
 Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2');
 Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
 Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
 Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
 Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');

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

@@ -2475,6 +2475,34 @@ converse.plugins.add('converse-muc', {
                     'num_unread': 0,
                     'num_unread': 0,
                     'num_unread_general': 0
                     'num_unread_general': 0
                 });
                 });
+            },
+
+            listMutedUsers () {
+                const stanza = $iq({
+                    type: 'get'
+                })
+                .c('blocklist', {xmlns: Strophe.NS.BLOCKING});
+                return api.sendIQ(stanza);
+            },
+
+            async onMuteUser (message) {
+                const jid = message.get('from');
+                const stanza = $iq({
+                    to: message.get('muc_domain'),
+                    from: _converse.connection.jid,
+                    type: 'set'
+                })
+                .c('block', {xmlns: Strophe.NS.BLOCKING})
+                .c('item', {jid});
+
+                await api.sendIQ(stanza);
+
+                const mapMessages = (msg) => new Promise((resolve) => {
+                    if (msg.get('from') === jid) {
+                        msg.destroy({ success: resolve, error: resolve })
+                    }
+                });
+                await Promise.all(Array.from(this.messages).map(mapMessages));
             }
             }
         });
         });