瀏覽代碼

Add an external API for sending presences

JC Brand 5 年之前
父節點
當前提交
c1efb0d2b4

+ 6 - 4
spec/controlbox.js

@@ -140,8 +140,9 @@
                 const view = _converse.xmppstatusview;
                 modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
                 modal.el.querySelector('[type="submit"]').click();
-                const last_stanza = _converse.connection.sent_stanzas.pop();
-                expect(Strophe.serialize(last_stanza)).toBe(
+                const sent_stanzas = _converse.connection.sent_stanzas;
+                const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
+                expect(Strophe.serialize(sent_presence)).toBe(
                     `<presence xmlns="jabber:client">`+
                         `<show>dnd</show>`+
                         `<priority>0</priority>`+
@@ -169,8 +170,9 @@
                 const msg = 'I am happy';
                 modal.el.querySelector('input[name="status_message"]').value = msg;
                 modal.el.querySelector('[type="submit"]').click();
-                const last_stanza = _converse.connection.sent_stanzas.pop();
-                expect(Strophe.serialize(last_stanza)).toBe(
+                const sent_stanzas = _converse.connection.sent_stanzas;
+                const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
+                expect(Strophe.serialize(sent_presence)).toBe(
                     `<presence xmlns="jabber:client">`+
                         `<status>I am happy</status>`+
                         `<priority>0</priority>`+

+ 17 - 10
spec/presence.js

@@ -8,6 +8,7 @@
     ], factory);
 } (this, function (jasmine, mock, test_utils) {
     "use strict";
+    const Strophe = converse.env.Strophe;
     const u = converse.env.utils;
     // See: https://xmpp.org/rfcs/rfc3921.html
 
@@ -37,7 +38,7 @@
         }));
 
         it("has a given priority", mock.initConverse((done, _converse) => {
-            let pres = _converse.xmppstatus.constructPresence('online', 'Hello world');
+            let pres = _converse.xmppstatus.constructPresence('online', null, 'Hello world');
             expect(pres.toLocaleString()).toBe(
                 `<presence xmlns="jabber:client">`+
                     `<status>Hello world</status>`+
@@ -46,7 +47,7 @@
                 `</presence>`
             );
             _converse.priority = 2;
-            pres = _converse.xmppstatus.constructPresence('away', 'Going jogging');
+            pres = _converse.xmppstatus.constructPresence('away', null, 'Going jogging');
             expect(pres.toLocaleString()).toBe(
                 `<presence xmlns="jabber:client">`+
                     `<show>away</show>`+
@@ -57,7 +58,7 @@
             );
 
             delete _converse.priority;
-            pres = _converse.xmppstatus.constructPresence('dnd', 'Doing taxes');
+            pres = _converse.xmppstatus.constructPresence('dnd', null, 'Doing taxes');
             expect(pres.toLocaleString()).toBe(
                 `<presence xmlns="jabber:client">`+
                     `<show>dnd</show>`+
@@ -75,8 +76,6 @@
                 async (done, _converse) => {
 
             test_utils.openControlBox(_converse);
-            const view = _converse.xmppstatusview;
-            spyOn(view.model, 'sendPresence').and.callThrough();
             spyOn(_converse.connection, 'send').and.callThrough();
 
             const cbview = _converse.chatboxviews.get('controlbox');
@@ -86,8 +85,10 @@
             const msg = 'My custom status';
             modal.el.querySelector('input[name="status_message"]').value = msg;
             modal.el.querySelector('[type="submit"]').click();
-            expect(view.model.sendPresence).toHaveBeenCalled();
-            expect(_converse.connection.send.calls.mostRecent().args[0].toLocaleString())
+
+            const sent_stanzas = _converse.connection.sent_stanzas;
+            let sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
+            expect(Strophe.serialize(sent_presence))
                 .toBe(`<presence xmlns="jabber:client">`+
                         `<status>My custom status</status>`+
                         `<priority>0</priority>`+
@@ -100,10 +101,16 @@
             await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "false", 1000);
             modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
             modal.el.querySelector('[type="submit"]').click();
-            expect(_converse.connection.send.calls.mostRecent().args[0].toLocaleString())
-                .toBe(`<presence xmlns="jabber:client"><show>dnd</show><status>My custom status</status><priority>0</priority>`+
+            await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).length === 2);
+            sent_presence = sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop();
+            expect(Strophe.serialize(sent_presence))
+                .toBe(
+                    `<presence xmlns="jabber:client">`+
+                        `<show>dnd</show>`+
+                        `<status>My custom status</status>`+
+                        `<priority>0</priority>`+
                         `<c hash="sha-1" node="https://conversejs.org" ver="Hxbsr5fazs62i+O0GxIXf2OEDNs=" xmlns="http://jabber.org/protocol/caps"/>`+
-                        `</presence>`)
+                    `</presence>`)
             done();
         }));
     });

+ 4 - 2
spec/xmppstatus.js

@@ -1,14 +1,16 @@
 (function (root, factory) {
     define(["jasmine", "mock"], factory);
 } (this, function (jasmine, mock) {
+    const u = converse.env.utils;
 
     return describe("The XMPPStatus model", function () {
 
-        it("won't send <show>online</show> when setting a custom status message", mock.initConverse((done, _converse) => {
+        it("won't send <show>online</show> when setting a custom status message",
+                mock.initConverse(async (done, _converse) => {
             _converse.xmppstatus.save({'status': 'online'});
             spyOn(_converse.connection, 'send');
             _converse.api.user.status.message.set("I'm also happy!");
-            expect(_converse.connection.send).toHaveBeenCalled();
+            await u.waitUntil(() => _converse.connection.send.calls.count());
             const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
             expect(stanza.childNodes.length).toBe(3);
             expect(stanza.querySelectorAll('status').length).toBe(1);

+ 1 - 1
src/converse-rosterview.js

@@ -834,7 +834,7 @@ converse.plugins.add('converse-rosterview', {
                 u.addClass('fa-spin', ev.target);
                 _converse.roster.data.save('version', null);
                 await _converse.roster.fetchFromServer();
-                _converse.xmppstatus.sendPresence();
+                api.user.presence.send();
                 u.removeClass('fa-spin', ev.target);
             },
 

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

@@ -90,7 +90,6 @@ const PROMISES = [
     'connectionInitialized',
     'initialized',
     'pluginsInitialized',
-    'statusInitialized'
 ];
 
 // Core plugins are whitelisted automatically
@@ -712,7 +711,6 @@ export const api = _converse.api = {
      * * [rosterContactsFetched](/docs/html/events.html#rosterContactsFetched)
      * * [rosterGroupsFetched](/docs/html/events.html#rosterGroupsFetched)
      * * [rosterInitialized](/docs/html/events.html#rosterInitialized)
-     * * [statusInitialized](/docs/html/events.html#statusInitialized)
      * * [roomsPanelRendered](/docs/html/events.html#roomsPanelRendered)
      *
      * The various plugins might also provide promises, and they do this by using the

+ 1 - 13
src/headless/converse-muc.js

@@ -852,7 +852,7 @@ converse.plugins.add('converse-muc', {
                     }
                 }
                 if (api.connection.connected()) {
-                    this.sendUnavailablePresence(exit_msg);
+                    api.user.presence.send('unavailable', this.getRoomJIDAndNick(), exit_msg);
                 }
                 u.safeSave(this.session, {'connection_status': converse.ROOMSTATUS.DISCONNECTED});
                 this.removeHandlers();
@@ -877,18 +877,6 @@ converse.plugins.add('converse-muc', {
                 return self && self.isModerator() && api.disco.supports(Strophe.NS.MODERATE, this.get('jid'));
             },
 
-            sendUnavailablePresence (exit_msg) {
-                const presence = $pres({
-                    type: "unavailable",
-                    from: _converse.connection.jid,
-                    to: this.getRoomJIDAndNick()
-                });
-                if (exit_msg !== null) {
-                    presence.c("status", exit_msg);
-                }
-                _converse.connection.sendPresence(presence);
-            },
-
             /**
              * Return an array of unique nicknames based on all occupants and messages in this MUC.
              * @private

+ 2 - 2
src/headless/converse-roster.js

@@ -80,7 +80,7 @@ converse.plugins.add('converse-roster', {
 
         _converse.sendInitialPresence = function () {
             if (_converse.send_initial_presence) {
-                _converse.xmppstatus.sendPresence();
+                api.user.presence.send();
             }
         };
 
@@ -771,7 +771,7 @@ converse.plugins.add('converse-roster', {
                     //
                     // As a workaround for now we simply send our presence again,
                     // otherwise we're treated as offline.
-                    _converse.xmppstatus.sendPresence();
+                    api.user.presence.send();
                 }
             },
 

+ 37 - 21
src/headless/converse-status.js

@@ -23,6 +23,7 @@ converse.plugins.add('converse-status', {
             default_state: 'online',
             priority: 0,
         });
+        api.promises.add(['statusInitialized']);
 
         _converse.XMPPStatus = Model.extend({
             defaults () {
@@ -35,7 +36,7 @@ converse.plugins.add('converse-status', {
                         return;
                     }
                     if ('status' in item.changed || 'status_message' in item.changed) {
-                        this.sendPresence(this.get('status'), this.get('status_message'));
+                        api.user.presence.send(this.get('status'), null, this.get('status_message'));
                     }
                 });
             },
@@ -49,12 +50,11 @@ converse.plugins.add('converse-status', {
                 return '';
             },
 
-            constructPresence (type, status_message) {
-                let presence;
+            constructPresence (type, to=null, status_message) {
                 type = isString(type) ? type : (this.get('status') || api.settings.get("default_state"));
                 status_message = isString(status_message) ? status_message : this.get('status_message');
-                // Most of these presence types are actually not explicitly sent,
-                // but I add all of them here for reference and future proofing.
+                let presence;
+                const attrs = {to};
                 if ((type === 'unavailable') ||
                         (type === 'probe') ||
                         (type === 'error') ||
@@ -62,14 +62,17 @@ converse.plugins.add('converse-status', {
                         (type === 'unsubscribed') ||
                         (type === 'subscribe') ||
                         (type === 'subscribed')) {
-                    presence = $pres({'type': type});
+                    attrs['type'] = type;
+                    presence = $pres(attrs);
                 } else if (type === 'offline') {
-                    presence = $pres({'type': 'unavailable'});
+                    attrs['type'] = 'unavailable';
+                    presence = $pres(attrs);
                 } else if (type === 'online') {
-                    presence = $pres();
+                    presence = $pres(attrs);
                 } else {
-                    presence = $pres().c('show').t(type).up();
+                    presence = $pres(attrs).c('show').t(type).up();
                 }
+
                 if (status_message) {
                     presence.c('status').t(status_message).up();
                 }
@@ -82,10 +85,6 @@ converse.plugins.add('converse-status', {
                     presence.c('idle', {xmlns: Strophe.NS.IDLE, since: idle_since.toISOString()});
                 }
                 return presence;
-            },
-
-            sendPresence (type, status_message) {
-                api.send(this.constructPresence(type, status_message));
             }
         });
 
@@ -118,7 +117,7 @@ converse.plugins.add('converse-status', {
             }
             if (_converse.idle) {
                 _converse.idle = false;
-                _converse.xmppstatus.sendPresence();
+                api.user.presence.send();
             }
             if (_converse.auto_changed_status === true) {
                 _converse.auto_changed_status = false;
@@ -148,7 +147,7 @@ converse.plugins.add('converse-status', {
                     _converse.idle_seconds > api.settings.get("idle_presence_timeout") &&
                     !_converse.idle) {
                 _converse.idle = true;
-                _converse.xmppstatus.sendPresence();
+                api.user.presence.send();
             }
             if (api.settings.get("auto_away") > 0 &&
                     _converse.idle_seconds > api.settings.get("auto_away") &&
@@ -245,21 +244,39 @@ converse.plugins.add('converse-status', {
 
         /************************ BEGIN API ************************/
         Object.assign(_converse.api.user, {
+            /**
+             * @namespace _converse.api.user.presence
+             * @memberOf _converse.api.user
+             */
+            presence: {
+                /**
+                 * Send out a presence stanza
+                 * @method _converse.api.user.presence.send
+                 * @param { String } type
+                 * @param { String } to
+                 * @param { String } [status] - An optional status message
+                 */
+                async send (type, to, status) {
+                    await api.waitUntil('statusInitialized');
+                    api.send(_converse.xmppstatus.constructPresence(type, to, status));
+                }
+            },
+
             /**
              * Set and get the user's chat status, also called their *availability*.
-             *
              * @namespace _converse.api.user.status
              * @memberOf _converse.api.user
              */
             status: {
-                /** Return the current user's availability status.
-                 *
+                /**
+                 * Return the current user's availability status.
                  * @method _converse.api.user.status.get
                  * @example _converse.api.user.status.get();
                  */
                 get () {
                     return _converse.xmppstatus.get('status');
                 },
+
                 /**
                  * The user's status can be set to one of the following values:
                  *
@@ -267,8 +284,8 @@ converse.plugins.add('converse-status', {
                  * @param {string} value The user's chat status (e.g. 'away', 'dnd', 'offline', 'online', 'unavailable' or 'xa')
                  * @param {string} [message] A custom status message
                  *
-                 * @example this._converse.api.user.status.set('dnd');
-                 * @example this._converse.api.user.status.set('dnd', 'In a meeting');
+                 * @example _converse.api.user.status.set('dnd');
+                 * @example _converse.api.user.status.set('dnd', 'In a meeting');
                  */
                 set (value, message) {
                     const data = {'status': value};
@@ -280,7 +297,6 @@ converse.plugins.add('converse-status', {
                     if (isString(message)) {
                         data.status_message = message;
                     }
-                    _converse.xmppstatus.sendPresence(value);
                     _converse.xmppstatus.save(data);
                 },