Browse Source

Allow multiple push services to be enabled and also allow disabling

JC Brand 7 years ago
parent
commit
a09333f82c
4 changed files with 251 additions and 117 deletions
  1. 82 36
      dist/converse.js
  2. 24 24
      docs/source/configuration.rst
  3. 61 16
      spec/push.js
  4. 84 41
      src/converse-push.js

+ 82 - 36
dist/converse.js

@@ -73353,54 +73353,100 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
             __ = _converse.__;
 
       _converse.api.settings.update({
-        'push_service': undefined,
-        'push_service_node': undefined,
-        'push_service_secret': undefined
+        'push_services': []
       });
 
-      function enablePush() {
-        if (_converse.session.get('push_enabled')) {
+      function disablePushService(push_service) {
+        if (!push_service.jid) {
           return;
         }
 
-        if (_converse.push_service && _converse.push_service_node) {
-          _converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service).then(identity => {
-            if (!identity) {
-              return _converse.log(`Not enabling push the service "${_converse.push_service}", it doesn't have the right disco identtiy.`, Strophe.LogLevel.WARN);
-            }
+        Promise.all([_converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)]).then(result => {
+          if (!result[0].length && !result[1].length) {
+            return _converse.log(`Not disabling push service "${push_service.jid}", no disco support from your server.`, Strophe.LogLevel.WARN);
+          }
 
-            return Promise.all([_converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service), _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)]).then(result => {
-              if (!result[0].length && !result[1].length) {
-                return _converse.log(`Not enabling push service "${_converse.push_service}", no disco support`, Strophe.LogLevel.WARN);
-              }
+          const stanza = $iq({
+            'type': 'set'
+          }).c('disable', {
+            'xmlns': Strophe.NS.PUSH,
+            'jid': push_service.jid
+          });
 
-              const stanza = $iq({
-                'type': 'set'
-              }).c('enable', {
-                'xmlns': Strophe.NS.PUSH,
-                'jid': _converse.push_service,
-                'node': _converse.push_service_node
-              });
+          if (push_service.node) {
+            stanza.attrs({
+              'node': push_service.node
+            });
+          }
 
-              if (_converse.push_service_secret) {
-                stanza.c('x', {
-                  'xmlns': Strophe.NS.XFORM,
-                  'type': 'submit'
-                }).c('field', {
-                  'var': 'FORM_TYPE'
-                }).c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up().c('field', {
-                  'var': 'secret'
-                }).c('value').t(_converse.push_service_secret);
-              }
+          _converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
+            _converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
+
+            _converse.log(e, Strophe.LogLevel.ERROR);
+          });
+        }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+      }
 
-              _converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
-                _converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
+      function enablePushService(push_service) {
+        if (!push_service.jid || !push_service.node) {
+          return;
+        }
 
-                _converse.log(e, Strophe.LogLevel.ERROR);
-              });
-            }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+        _converse.api.disco.getIdentity('pubsub', 'push', push_service.jid).then(identity => {
+          if (!identity) {
+            return _converse.log(`Not enabling push the service "${push_service.jid}", it doesn't have the right disco identtiy.`, Strophe.LogLevel.WARN);
+          }
+
+          return Promise.all([_converse.api.disco.supports(Strophe.NS.PUSH, push_service.jid), _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)]).then(result => {
+            if (!result[0].length && !result[1].length) {
+              return _converse.log(`Not enabling push service "${push_service.jid}", no disco support from your server.`, Strophe.LogLevel.WARN);
+            }
+
+            const stanza = $iq({
+              'type': 'set'
+            }).c('enable', {
+              'xmlns': Strophe.NS.PUSH,
+              'jid': push_service.jid,
+              'node': push_service.node
+            });
+
+            if (push_service.secret) {
+              stanza.c('x', {
+                'xmlns': Strophe.NS.XFORM,
+                'type': 'submit'
+              }).c('field', {
+                'var': 'FORM_TYPE'
+              }).c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up().c('field', {
+                'var': 'secret'
+              }).c('value').t(push_service.secret);
+            }
+
+            _converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
+              _converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
+
+              _converse.log(e, Strophe.LogLevel.ERROR);
+            });
           }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+        }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+      }
+
+      function enablePush() {
+        if (_converse.session.get('push_enabled')) {
+          // XXX: this code is still a bit naive. We set push_enabled
+          // to true as soon as the first push service has been set.
+          //
+          // When enabling or disabling multiple push services,
+          // we won't wait until we have confirmation that all have been set.
+          return;
         }
+
+        const enabled_services = _.reject(_converse.push_services, 'disable');
+
+        _.each(enabled_services, enablePushService);
+
+        const disabled_services = _.filter(_converse.push_services, 'disable');
+
+        _.each(disabled_services, disablePushService);
       }
 
       _converse.api.listen.on('statusInitialized', enablePush);

+ 24 - 24
docs/source/configuration.rst

@@ -1068,38 +1068,38 @@ providers_link
 The hyperlink on the registration form which points to a directory of public
 XMPP servers.
 
-push_service
-------------
-
-* Default: ``undefined``
-
-This option allows you to specify a URI for the push notifications service
-(called an "App Server" by `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
+push_services
+-------------
 
-If provided, together with a `push_service_node`_, then Converse will instruct
-the user's XMPP server to send push notificatiosn to that URI.
+* Default: ``[]``
 
-push_service_node
------------------
+This option lets you enable or disable so-called push notification "App Servers"
+(as per `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
 
-* Default: ``undefined``
+For each "App Server" an object needs to be passed in. When enabling, you need
+to specify ``jid`` and ``node`` values. You can also provide a
+``secret``, if required by your App Server.
 
-This is the PubSub node of the push notifications service (aka "App Server") specified with the
-`push_service`_ setting.
+When disabling, you need to specify at least a ``jid`` and set ``disabled`` to
+``true``. This will disable notifications to all pubsub nodes on that "App
+Server". If you want to disable only a particular node, then specify a ``node``
+value as well.
 
-Push notifications will be sent to this node. If this value is not set, then
-push notifications won't be sent out.
-
-push_service_secret
--------------------
+For example:
 
-* Default: ``undefined``
 
-Some push notification services (aka "App Servers") require a secret token to
-be used when sending out notifications.
+.. code-block:: javascript
 
-This setting enables you to provide such a secret to Converse which will
-forward it to your XMPP server to be included in push notifications.
+        converse.initialize({
+            'push_services':  [{
+                'jid': 'push-4@client.example',
+                'node': 'yxs32uqsflafdk3iuqo',
+                'disable': true
+            }, {
+                'jid': 'push-5@client.example',
+                'node': 'yxs32uqsflafdk3iuqo',
+            }]
+        });
 
 root
 ----

+ 61 - 16
spec/push.js

@@ -8,22 +8,22 @@
 
     describe("XEP-0357 Push Notifications", function () {
 
-        it("can be enabled by specifying a push_service and push_service_node",
-            mock.initConverseWithPromises(null, 
+        it("can be enabled",
+            mock.initConverseWithPromises(null,
                 ['rosterGroupsFetched'], {
-                    'push_service': 'push-5@client.example',
-                    'push_service_node': 'yxs32uqsflafdk3iuqo' 
+                    'push_services': [{
+                        'jid': 'push-5@client.example',
+                        'node': 'yxs32uqsflafdk3iuqo'
+                    }]
                 }, function (done, _converse) {
 
             const IQ_stanzas = _converse.connection.IQ_stanzas;
             let stanza;
 
-            expect(_converse.push_service).toBe('push-5@client.example');
-            expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
             expect(_converse.session.get('push_enabled')).toBeFalsy();
 
             test_utils.waitUntilDiscoConfirmed(
-                _converse, _converse.push_service,
+                _converse, _converse.push_services[0].jid,
                 [{'category': 'pubsub', 'type':'push'}],
                 ['urn:xmpp:push:0'], [], 'info')
             .then(() => test_utils.waitUntilDiscoConfirmed(
@@ -58,25 +58,70 @@
             }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
         }));
 
+        it("can be disabled",
+            mock.initConverseWithPromises(null,
+                ['rosterGroupsFetched'], {
+                    'push_services': [{
+                        'jid': 'push-5@client.example',
+                        'node': 'yxs32uqsflafdk3iuqo',
+                        'disable': true
+                    }]
+                }, function (done, _converse) {
+
+            const IQ_stanzas = _converse.connection.IQ_stanzas;
+            let stanza;
+
+            expect(_converse.session.get('push_enabled')).toBeFalsy();
+
+            test_utils.waitUntilDiscoConfirmed(
+                _converse,
+                _converse.bare_jid,
+                [{'category': 'account', 'type':'registered'}],
+                ['urn:xmpp:push:0'], [], 'info')
+            .then(() => {
+                return test_utils.waitUntil(() => {
+                    const node = _.filter(IQ_stanzas, function (iq) {
+                        return iq.nodeTree.querySelector('iq[type="set"] disable[xmlns="urn:xmpp:push:0"]');
+                    }).pop();
+                    if (node) {
+                        stanza = node.nodeTree;
+                        return true;
+                    }
+                })
+            }).then(() => {
+                expect(stanza.outerHTML).toEqual(
+                    `<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
+                        '<disable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo"/>'+
+                    '</iq>'
+                )
+                _converse.connection._dataRecv(test_utils.createRequest($iq({
+                    'to': _converse.connection.jid,
+                    'type': 'result',
+                    'id': stanza.getAttribute('id')
+                })));
+                return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
+            }).then(() => {
+                done();
+            }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+        }));
+
 
         it("can require a secret token to be included",
-            mock.initConverseWithPromises(null, 
+            mock.initConverseWithPromises(null,
                 ['rosterGroupsFetched'], {
-                    'push_service': 'push-5@client.example',
-                    'push_service_node': 'yxs32uqsflafdk3iuqo',
-                    'push_service_secret': 'eruio234vzxc2kla-91'
+                    'push_services': [{
+                        'jid': 'push-5@client.example',
+                        'node': 'yxs32uqsflafdk3iuqo',
+                        'secret': 'eruio234vzxc2kla-91'
+                    }]
                 }, function (done, _converse) {
 
             const IQ_stanzas = _converse.connection.IQ_stanzas;
             let stanza;
-
-            expect(_converse.push_service).toBe('push-5@client.example');
-            expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
-            expect(_converse.push_service_secret).toBe('eruio234vzxc2kla-91');
             expect(_converse.session.get('push_enabled')).toBeFalsy();
 
             test_utils.waitUntilDiscoConfirmed(
-                _converse, _converse.push_service,
+                _converse, _converse.push_services[0].jid,
                 [{'category': 'pubsub', 'type':'push'}],
                 ['urn:xmpp:push:0'], [], 'info')
             .then(() => test_utils.waitUntilDiscoConfirmed(

+ 84 - 41
src/converse-push.js

@@ -16,7 +16,7 @@
 
     Strophe.addNamespace('PUSH', 'urn:xmpp:push:0');
 
-    
+
     converse.plugins.add('converse-push', {
 
         initialize () {
@@ -27,56 +27,99 @@
                   { __ } = _converse;
 
             _converse.api.settings.update({
-                'push_service': undefined,
-                'push_service_node': undefined,
-                'push_service_secret': undefined
+                'push_services': [],
             });
 
-            function enablePush() {
-                if (_converse.session.get('push_enabled')) {
+            function disablePushService (push_service) {
+                if (!push_service.jid) {
+                    return;
+                }
+                Promise.all([
+                    _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
+                ]).then((result) => {
+                    if (!result[0].length && !result[1].length) {
+                        return _converse.log(
+                            `Not disabling push service "${push_service.jid}", no disco support from your server.`,
+                            Strophe.LogLevel.WARN
+                        );
+                    }
+                    const stanza = $iq({'type': 'set'})
+                        .c('disable', {
+                            'xmlns': Strophe.NS.PUSH,
+                            'jid': push_service.jid,
+                        });
+                    if (push_service.node) {
+                        stanza.attrs({'node': push_service.node});
+                    }
+
+                    _converse.api.sendIQ(stanza)
+                        .then(() => _converse.session.set('push_enabled', true))
+                        .catch((e) => {
+                            _converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
+                            _converse.log(e, Strophe.LogLevel.ERROR);
+                        });
+                }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+            }
+
+            function enablePushService (push_service) {
+                if (!push_service.jid || !push_service.node) {
                     return;
                 }
-                if (_converse.push_service && _converse.push_service_node) {
-                    _converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service)
-                    .then((identity) => {
-                        if (!identity) {
+                _converse.api.disco.getIdentity('pubsub', 'push', push_service.jid)
+                .then((identity) => {
+                    if (!identity) {
+                        return _converse.log(
+                            `Not enabling push the service "${push_service.jid}", it doesn't have the right disco identtiy.`,
+                            Strophe.LogLevel.WARN
+                        );
+                    }
+                    return Promise.all([
+                        _converse.api.disco.supports(Strophe.NS.PUSH, push_service.jid),
+                        _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
+                    ]).then((result) => {
+                        if (!result[0].length && !result[1].length) {
                             return _converse.log(
-                                `Not enabling push the service "${_converse.push_service}", it doesn't have the right disco identtiy.`,
+                                `Not enabling push service "${push_service.jid}", no disco support from your server.`,
                                 Strophe.LogLevel.WARN
                             );
                         }
-                        return Promise.all([
-                            _converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service),
-                            _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
-                        ]).then((result) => {
-                            if (!result[0].length && !result[1].length) {
-                                return _converse.log(
-                                    `Not enabling push service "${_converse.push_service}", no disco support`,
-                                    Strophe.LogLevel.WARN
-                                );
-                            }
-                            const stanza = $iq({'type': 'set'})
-                                .c('enable', {
-                                    'xmlns': Strophe.NS.PUSH,
-                                    'jid': _converse.push_service,
-                                    'node': _converse.push_service_node
-                                });
-                            if (_converse.push_service_secret) {
-                                stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
-                                    .c('field', {'var': 'FORM_TYPE'})
-                                        .c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up()
-                                    .c('field', {'var': 'secret'})
-                                        .c('value').t(_converse.push_service_secret);
-                            }
-                            _converse.api.sendIQ(stanza)
-                                .then(() => _converse.session.set('push_enabled', true))
-                                .catch((e) => {
-                                    _converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
-                                    _converse.log(e, Strophe.LogLevel.ERROR);
-                                });
-                        }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+                        const stanza = $iq({'type': 'set'})
+                            .c('enable', {
+                                'xmlns': Strophe.NS.PUSH,
+                                'jid': push_service.jid,
+                                'node': push_service.node
+                            });
+                        if (push_service.secret) {
+                            stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
+                                .c('field', {'var': 'FORM_TYPE'})
+                                    .c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up()
+                                .c('field', {'var': 'secret'})
+                                    .c('value').t(push_service.secret);
+                        }
+                        _converse.api.sendIQ(stanza)
+                            .then(() => _converse.session.set('push_enabled', true))
+                            .catch((e) => {
+                                _converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
+                                _converse.log(e, Strophe.LogLevel.ERROR);
+                            });
                     }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+                }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+            }
+
+            function enablePush () {
+                if (_converse.session.get('push_enabled')) {
+                    // XXX: this code is still a bit naive. We set push_enabled
+                    // to true as soon as the first push service has been set.
+                    //
+                    // When enabling or disabling multiple push services,
+                    // we won't wait until we have confirmation that all have been set.
+                    return;
                 }
+                const enabled_services = _.reject(_converse.push_services, 'disable');
+                _.each(enabled_services, enablePushService);
+
+                const disabled_services = _.filter(_converse.push_services, 'disable');
+                _.each(disabled_services, disablePushService);
             }
             _converse.api.listen.on('statusInitialized', enablePush);
         }