Browse Source

muc-views: Present challenge to `destroy` confirmation

And also allow the user to specify the JID to where the conversation has
moved to.
JC Brand 5 years ago
parent
commit
c9084e4ed5
2 changed files with 116 additions and 51 deletions
  1. 62 11
      spec/muc.js
  2. 54 40
      src/converse-muc-views.js

+ 62 - 11
spec/muc.js

@@ -3836,27 +3836,43 @@
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'lounge@montague.lit';
                 const muc_jid = 'lounge@montague.lit';
+                const new_muc_jid = 'foyer@montague.lit';
                 await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
                 await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
-                const view = _converse.api.chatviews.get(muc_jid);
-                spyOn(_converse.api, 'confirm').and.callFake(() => Promise.resolve(true));
-                const textarea = view.el.querySelector('.chat-textarea');
-                textarea.value = '/destroy bored';
+                let view = _converse.api.chatviews.get(muc_jid);
+                spyOn(_converse.api, 'confirm').and.callThrough();
+                let textarea = view.el.querySelector('.chat-textarea');
+                textarea.value = '/destroy';
                 view.onFormSubmitted(new Event('submit'));
                 view.onFormSubmitted(new Event('submit'));
-
-                const sent_IQs = _converse.connection.IQ_stanzas;
-                const sent_IQ = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('destroy')).pop());
+                let modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
+                await u.waitUntil(() => u.isVisible(modal));
+
+                let challenge_el = modal.querySelector('[name="challenge"]');
+                challenge_el.value = muc_jid+'e';
+                const reason_el = modal.querySelector('[name="reason"]');
+                reason_el.value = 'Moved to a new location';
+                const newjid_el = modal.querySelector('[name="newjid"]');
+                newjid_el.value = new_muc_jid;
+                let submit = modal.querySelector('[type="submit"]');
+                submit.click();
+                expect(u.isVisible(modal)).toBeTruthy();
+                expect(u.hasClass('error', challenge_el)).toBeTruthy();
+                challenge_el.value = muc_jid;
+                submit.click();
+
+                let sent_IQs = _converse.connection.IQ_stanzas;
+                let sent_IQ = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('destroy')).pop());
                 expect(Strophe.serialize(sent_IQ)).toBe(
                 expect(Strophe.serialize(sent_IQ)).toBe(
-                    `<iq id="${sent_IQ.getAttribute('id')}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
+                    `<iq id="${sent_IQ.getAttribute('id')}" to="${muc_jid}" type="set" xmlns="jabber:client">`+
                         `<query xmlns="http://jabber.org/protocol/muc#owner">`+
                         `<query xmlns="http://jabber.org/protocol/muc#owner">`+
-                            `<destroy>`+
+                            `<destroy jid="${new_muc_jid}">`+
                                 `<reason>`+
                                 `<reason>`+
-                                    `bored`+
+                                    `Moved to a new location`+
                                 `</reason>`+
                                 `</reason>`+
                             `</destroy>`+
                             `</destroy>`+
                         `</query>`+
                         `</query>`+
                     `</iq>`);
                     `</iq>`);
 
 
-                const result_stanza = $iq({
+                let result_stanza = $iq({
                     'type': 'result',
                     'type': 'result',
                     'id': sent_IQ.getAttribute('id'),
                     'id': sent_IQ.getAttribute('id'),
                     'from': view.model.get('jid'),
                     'from': view.model.get('jid'),
@@ -3868,6 +3884,41 @@
                 await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED));
                 await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED));
                 await u.waitUntil(() => _converse.chatboxes.length === 1);
                 await u.waitUntil(() => _converse.chatboxes.length === 1);
                 expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
                 expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
+
+                // Try again without reason or new JID
+                _converse.connection.IQ_stanzas = [];
+                sent_IQs = _converse.connection.IQ_stanzas;
+                await test_utils.openAndEnterChatRoom(_converse, new_muc_jid, 'romeo');
+                view = _converse.api.chatviews.get(new_muc_jid);
+                textarea = view.el.querySelector('.chat-textarea');
+                textarea.value = '/destroy';
+                view.onFormSubmitted(new Event('submit'));
+                modal = await u.waitUntil(() => document.querySelector('.modal-dialog'));
+                await u.waitUntil(() => u.isVisible(modal));
+
+                challenge_el = modal.querySelector('[name="challenge"]');
+                challenge_el.value = new_muc_jid;
+                submit = modal.querySelector('[type="submit"]');
+                submit.click();
+
+                sent_IQ = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector('destroy')).pop());
+                expect(Strophe.serialize(sent_IQ)).toBe(
+                    `<iq id="${sent_IQ.getAttribute('id')}" to="${new_muc_jid}" type="set" xmlns="jabber:client">`+
+                        `<query xmlns="http://jabber.org/protocol/muc#owner">`+
+                            `<destroy/>`+
+                        `</query>`+
+                    `</iq>`);
+
+                result_stanza = $iq({
+                    'type': 'result',
+                    'id': sent_IQ.getAttribute('id'),
+                    'from': view.model.get('jid'),
+                    'to': _converse.connection.jid
+                });
+                expect(_converse.chatboxes.length).toBe(2);
+                _converse.connection._dataRecv(test_utils.createRequest(result_stanza));
+                await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED));
+                await u.waitUntil(() => _converse.chatboxes.length === 1);
                 done();
                 done();
             }));
             }));
         });
         });

+ 54 - 40
src/converse-muc-views.js

@@ -1014,19 +1014,14 @@ converse.plugins.add('converse-muc-views', {
                     if (_converse.show_retraction_warning) {
                     if (_converse.show_retraction_warning) {
                         messages[1] = retraction_warning;
                         messages[1] = retraction_warning;
                     }
                     }
-                    const result = await api.confirm(__('Confirm'), messages);
-                    if (result) {
-                        this.retractOwnMessage(message);
-                    }
+                    !!(await api.confirm(__('Confirm'), messages)) && this.retractOwnMessage(message);
                 } else if (await message.mayBeModerated()) {
                 } else if (await message.mayBeModerated()) {
                     if (message.get('sender') === 'me') {
                     if (message.get('sender') === 'me') {
                         let messages = [__('Are you sure you want to retract this message?')];
                         let messages = [__('Are you sure you want to retract this message?')];
                         if (_converse.show_retraction_warning) {
                         if (_converse.show_retraction_warning) {
                             messages = [messages[0], retraction_warning, messages[1]]
                             messages = [messages[0], retraction_warning, messages[1]]
                         }
                         }
-                        if (await api.confirm(__('Confirm'), messages)) {
-                            this.retractOtherMessage(message);
-                        }
+                        !!(await api.confirm(__('Confirm'), messages)) && this.retractOtherMessage(message);
                     } else {
                     } else {
                         let messages = [
                         let messages = [
                             __('You are about to retract this message.'),
                             __('You are about to retract this message.'),
@@ -1040,9 +1035,7 @@ converse.plugins.add('converse-muc-views', {
                             messages,
                             messages,
                             __('Optional reason')
                             __('Optional reason')
                         );
                         );
-                        if (reason !== false) {
-                            this.retractOtherMessage(message, reason);
-                        }
+                        (reason !== false) && this.retractOtherMessage(message, reason);
                     }
                     }
                 } else {
                 } else {
                     const err_msg = __(`Sorry, you're not allowed to retract this message`);
                     const err_msg = __(`Sorry, you're not allowed to retract this message`);
@@ -1158,31 +1151,6 @@ converse.plugins.add('converse-muc-views', {
                     });
                     });
                 }
                 }
 
 
-                const conn_status = this.model.session.get('connection_status');
-                if (conn_status === converse.ROOMSTATUS.ENTERED) {
-                    const allowed_commands = this.getAllowedCommands();
-                    if (allowed_commands.includes('modtools')) {
-                        buttons.push({
-                            'i18n_text': __('Moderate'),
-                            'i18n_title': __('Moderate this groupchat'),
-                            'handler': () => this.showModeratorToolsModal(),
-                            'a_class': 'moderate-chatroom-button',
-                            'icon_class': 'fa-user-cog',
-                            'name': 'moderate'
-                        });
-                    }
-                    if (allowed_commands.includes('destroy')) {
-                        buttons.push({
-                            'i18n_text': __('Destroy'),
-                            'i18n_title': __('Remove this groupchat'),
-                            'handler': ev => this.destroy(ev),
-                            'a_class': 'destroy-chatroom-button',
-                            'icon_class': 'fa-trash',
-                            'name': 'destroy'
-                        });
-                    }
-                }
-
                 if (this.model.invitesAllowed()) {
                 if (this.model.invitesAllowed()) {
                     buttons.push({
                     buttons.push({
                         'i18n_text': __('Invite'),
                         'i18n_text': __('Invite'),
@@ -1208,6 +1176,32 @@ converse.plugins.add('converse-muc-views', {
                     });
                     });
                 }
                 }
 
 
+
+                const conn_status = this.model.session.get('connection_status');
+                if (conn_status === converse.ROOMSTATUS.ENTERED) {
+                    const allowed_commands = this.getAllowedCommands();
+                    if (allowed_commands.includes('modtools')) {
+                        buttons.push({
+                            'i18n_text': __('Moderate'),
+                            'i18n_title': __('Moderate this groupchat'),
+                            'handler': () => this.showModeratorToolsModal(),
+                            'a_class': 'moderate-chatroom-button',
+                            'icon_class': 'fa-user-cog',
+                            'name': 'moderate'
+                        });
+                    }
+                    if (allowed_commands.includes('destroy')) {
+                        buttons.push({
+                            'i18n_text': __('Destroy'),
+                            'i18n_title': __('Remove this groupchat'),
+                            'handler': ev => this.destroy(ev),
+                            'a_class': 'destroy-chatroom-button',
+                            'icon_class': 'fa-trash',
+                            'name': 'destroy'
+                        });
+                    }
+                }
+
                 if (!api.settings.get("singleton")) {
                 if (!api.settings.get("singleton")) {
                     buttons.push({
                     buttons.push({
                         'i18n_text': __('Leave'),
                         'i18n_text': __('Leave'),
@@ -1532,10 +1526,30 @@ converse.plugins.add('converse-muc-views', {
                 }
                 }
             },
             },
 
 
-            async destroy (reason, new_jid) {
-                const message = [__('Are you sure you want to destroy this groupchat?')];
-                if (await api.confirm(__('Confirm'), message)) {
-                    return this.model.sendDestroyIQ(reason, new_jid).then(() => this.close())
+            async destroy () {
+                const messages = [__('Are you sure you want to destroy this groupchat?')];
+                let fields = [{
+                    'name': 'challenge',
+                    'label': __('Please enter the XMPP address of this groupchat to confirm'),
+                    'challenge': this.model.get('jid'),
+                    'placeholder': __('name@example.org'),
+                    'required': true
+                }, {
+                    'name': 'reason',
+                    'label': __('Optional reason for destroying this groupchat'),
+                    'placeholder': __('Reason')
+                }, {
+                    'name': 'newjid',
+                    'label': __('Optional XMPP address for a new groupchat that replaces this one'),
+                    'placeholder': __('replacement@example.org')
+                }];
+                try {
+                    fields = await api.confirm(__('Confirm'), messages, fields);
+                    const reason = fields.filter(f => f.name === 'reason').pop()?.value;
+                    const newjid = fields.filter(f => f.name === 'newjid').pop()?.value;
+                    return this.model.sendDestroyIQ(reason, newjid).then(() => this.close())
+                } catch (e) {
+                    log.error(e);
                 }
                 }
             },
             },
 
 
@@ -1583,7 +1597,7 @@ converse.plugins.add('converse-muc-views', {
                         if (!this.verifyAffiliations(['owner'])) {
                         if (!this.verifyAffiliations(['owner'])) {
                             break;
                             break;
                         }
                         }
-                        this.destroy(args).catch(e => this.onCommandError(e));
+                        this.destroy().catch(e => this.onCommandError(e));
                         break;
                         break;
                     }
                     }
                     case 'help': {
                     case 'help': {