Allow multiple push services to be enabled and also allow disabling
This commit is contained in:
parent
5954cd8f29
commit
a09333f82c
118
dist/converse.js
vendored
118
dist/converse.js
vendored
@ -73353,54 +73353,100 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
|||||||
__ = _converse.__;
|
__ = _converse.__;
|
||||||
|
|
||||||
_converse.api.settings.update({
|
_converse.api.settings.update({
|
||||||
'push_service': undefined,
|
'push_services': []
|
||||||
'push_service_node': undefined,
|
|
||||||
'push_service_secret': undefined
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function enablePush() {
|
function disablePushService(push_service) {
|
||||||
if (_converse.session.get('push_enabled')) {
|
if (!push_service.jid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_converse.push_service && _converse.push_service_node) {
|
Promise.all([_converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)]).then(result => {
|
||||||
_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service).then(identity => {
|
if (!result[0].length && !result[1].length) {
|
||||||
if (!identity) {
|
return _converse.log(`Not disabling push service "${push_service.jid}", no disco support from your server.`, Strophe.LogLevel.WARN);
|
||||||
return _converse.log(`Not enabling push the service "${_converse.push_service}", it doesn't have the right disco identtiy.`, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 => {
|
const stanza = $iq({
|
||||||
if (!result[0].length && !result[1].length) {
|
'type': 'set'
|
||||||
return _converse.log(`Not enabling push service "${_converse.push_service}", no disco support`, Strophe.LogLevel.WARN);
|
}).c('enable', {
|
||||||
}
|
'xmlns': Strophe.NS.PUSH,
|
||||||
|
'jid': push_service.jid,
|
||||||
|
'node': push_service.node
|
||||||
|
});
|
||||||
|
|
||||||
const stanza = $iq({
|
if (push_service.secret) {
|
||||||
'type': 'set'
|
stanza.c('x', {
|
||||||
}).c('enable', {
|
'xmlns': Strophe.NS.XFORM,
|
||||||
'xmlns': Strophe.NS.PUSH,
|
'type': 'submit'
|
||||||
'jid': _converse.push_service,
|
}).c('field', {
|
||||||
'node': _converse.push_service_node
|
'var': 'FORM_TYPE'
|
||||||
});
|
}).c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up().c('field', {
|
||||||
|
'var': 'secret'
|
||||||
|
}).c('value').t(push_service.secret);
|
||||||
|
}
|
||||||
|
|
||||||
if (_converse.push_service_secret) {
|
_converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
|
||||||
stanza.c('x', {
|
_converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
|
||||||
'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(e, Strophe.LogLevel.ERROR);
|
||||||
_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));
|
|
||||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
}).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);
|
_converse.api.listen.on('statusInitialized', enablePush);
|
||||||
|
@ -1068,38 +1068,38 @@ providers_link
|
|||||||
The hyperlink on the registration form which points to a directory of public
|
The hyperlink on the registration form which points to a directory of public
|
||||||
XMPP servers.
|
XMPP servers.
|
||||||
|
|
||||||
push_service
|
push_services
|
||||||
------------
|
-------------
|
||||||
|
|
||||||
* Default: ``undefined``
|
* Default: ``[]``
|
||||||
|
|
||||||
This option allows you to specify a URI for the push notifications service
|
This option lets you enable or disable so-called push notification "App Servers"
|
||||||
(called an "App Server" by `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
|
(as per `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
|
||||||
|
|
||||||
If provided, together with a `push_service_node`_, then Converse will instruct
|
For each "App Server" an object needs to be passed in. When enabling, you need
|
||||||
the user's XMPP server to send push notificatiosn to that URI.
|
to specify ``jid`` and ``node`` values. You can also provide a
|
||||||
|
``secret``, if required by your App Server.
|
||||||
|
|
||||||
push_service_node
|
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.
|
||||||
|
|
||||||
* Default: ``undefined``
|
For example:
|
||||||
|
|
||||||
This is the PubSub node of the push notifications service (aka "App Server") specified with the
|
|
||||||
`push_service`_ setting.
|
|
||||||
|
|
||||||
Push notifications will be sent to this node. If this value is not set, then
|
.. code-block:: javascript
|
||||||
push notifications won't be sent out.
|
|
||||||
|
|
||||||
push_service_secret
|
converse.initialize({
|
||||||
-------------------
|
'push_services': [{
|
||||||
|
'jid': 'push-4@client.example',
|
||||||
* Default: ``undefined``
|
'node': 'yxs32uqsflafdk3iuqo',
|
||||||
|
'disable': true
|
||||||
Some push notification services (aka "App Servers") require a secret token to
|
}, {
|
||||||
be used when sending out notifications.
|
'jid': 'push-5@client.example',
|
||||||
|
'node': 'yxs32uqsflafdk3iuqo',
|
||||||
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.
|
});
|
||||||
|
|
||||||
root
|
root
|
||||||
----
|
----
|
||||||
|
75
spec/push.js
75
spec/push.js
@ -8,22 +8,22 @@
|
|||||||
|
|
||||||
describe("XEP-0357 Push Notifications", function () {
|
describe("XEP-0357 Push Notifications", function () {
|
||||||
|
|
||||||
it("can be enabled by specifying a push_service and push_service_node",
|
it("can be enabled",
|
||||||
mock.initConverseWithPromises(null,
|
mock.initConverseWithPromises(null,
|
||||||
['rosterGroupsFetched'], {
|
['rosterGroupsFetched'], {
|
||||||
'push_service': 'push-5@client.example',
|
'push_services': [{
|
||||||
'push_service_node': 'yxs32uqsflafdk3iuqo'
|
'jid': 'push-5@client.example',
|
||||||
|
'node': 'yxs32uqsflafdk3iuqo'
|
||||||
|
}]
|
||||||
}, function (done, _converse) {
|
}, function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
let stanza;
|
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();
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
test_utils.waitUntilDiscoConfirmed(
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
_converse, _converse.push_service,
|
_converse, _converse.push_services[0].jid,
|
||||||
[{'category': 'pubsub', 'type':'push'}],
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
['urn:xmpp:push:0'], [], 'info')
|
['urn:xmpp:push:0'], [], 'info')
|
||||||
.then(() => test_utils.waitUntilDiscoConfirmed(
|
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||||
@ -58,25 +58,70 @@
|
|||||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("can be disabled",
|
||||||
it("can require a secret token to be included",
|
|
||||||
mock.initConverseWithPromises(null,
|
mock.initConverseWithPromises(null,
|
||||||
['rosterGroupsFetched'], {
|
['rosterGroupsFetched'], {
|
||||||
'push_service': 'push-5@client.example',
|
'push_services': [{
|
||||||
'push_service_node': 'yxs32uqsflafdk3iuqo',
|
'jid': 'push-5@client.example',
|
||||||
'push_service_secret': 'eruio234vzxc2kla-91'
|
'node': 'yxs32uqsflafdk3iuqo',
|
||||||
|
'disable': true
|
||||||
|
}]
|
||||||
}, function (done, _converse) {
|
}, function (done, _converse) {
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
let stanza;
|
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();
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
test_utils.waitUntilDiscoConfirmed(
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
_converse, _converse.push_service,
|
_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,
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'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.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.push_services[0].jid,
|
||||||
[{'category': 'pubsub', 'type':'push'}],
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
['urn:xmpp:push:0'], [], 'info')
|
['urn:xmpp:push:0'], [], 'info')
|
||||||
.then(() => test_utils.waitUntilDiscoConfirmed(
|
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||||
|
@ -27,56 +27,99 @@
|
|||||||
{ __ } = _converse;
|
{ __ } = _converse;
|
||||||
|
|
||||||
_converse.api.settings.update({
|
_converse.api.settings.update({
|
||||||
'push_service': undefined,
|
'push_services': [],
|
||||||
'push_service_node': undefined,
|
|
||||||
'push_service_secret': undefined
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function enablePush() {
|
function disablePushService (push_service) {
|
||||||
if (_converse.session.get('push_enabled')) {
|
if (!push_service.jid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_converse.push_service && _converse.push_service_node) {
|
Promise.all([
|
||||||
_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service)
|
_converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
|
||||||
.then((identity) => {
|
]).then((result) => {
|
||||||
if (!identity) {
|
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;
|
||||||
|
}
|
||||||
|
_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(
|
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
|
Strophe.LogLevel.WARN
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Promise.all([
|
const stanza = $iq({'type': 'set'})
|
||||||
_converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service),
|
.c('enable', {
|
||||||
_converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
|
'xmlns': Strophe.NS.PUSH,
|
||||||
]).then((result) => {
|
'jid': push_service.jid,
|
||||||
if (!result[0].length && !result[1].length) {
|
'node': push_service.node
|
||||||
return _converse.log(
|
});
|
||||||
`Not enabling push service "${_converse.push_service}", no disco support`,
|
if (push_service.secret) {
|
||||||
Strophe.LogLevel.WARN
|
stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
|
||||||
);
|
.c('field', {'var': 'FORM_TYPE'})
|
||||||
}
|
.c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up()
|
||||||
const stanza = $iq({'type': 'set'})
|
.c('field', {'var': 'secret'})
|
||||||
.c('enable', {
|
.c('value').t(push_service.secret);
|
||||||
'xmlns': Strophe.NS.PUSH,
|
}
|
||||||
'jid': _converse.push_service,
|
_converse.api.sendIQ(stanza)
|
||||||
'node': _converse.push_service_node
|
.then(() => _converse.session.set('push_enabled', true))
|
||||||
});
|
.catch((e) => {
|
||||||
if (_converse.push_service_secret) {
|
_converse.log(`Could not enable push service for ${push_service.jid}`, Strophe.LogLevel.ERROR);
|
||||||
stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
|
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||||
.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));
|
|
||||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
}).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);
|
_converse.api.listen.on('statusInitialized', enablePush);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user