Refactor converse-api.query
and the RSM class
- The `converse.api.query` method now no longer accepts an RSM instance. - The RSM class now separates `query` parameters from `result` attributes - Improve JSDoc docs and remove need to make `converse-rsm` a plugin - Add typedefs for the options expected by RSM and `api.archive.query`
This commit is contained in:
parent
e7a3bb87c6
commit
b5783c0668
@ -33,6 +33,7 @@ Soon we'll deprecate the latter, so prepare now.
|
|||||||
- #2201: added html to converse.env
|
- #2201: added html to converse.env
|
||||||
- #2213: added CustomElement to converse.env
|
- #2213: added CustomElement to converse.env
|
||||||
- #2220: fix rendering of emojis in case `use_system_emojis == false` (again).
|
- #2220: fix rendering of emojis in case `use_system_emojis == false` (again).
|
||||||
|
- The `api.archive.query` method no longer accepts an RSM instance as argument.
|
||||||
- The plugin `converse-uniview` has been removed and its functionality merged into `converse-chatboxviews`
|
- The plugin `converse-uniview` has been removed and its functionality merged into `converse-chatboxviews`
|
||||||
- Removed the mockups from the project. Recommended to use tests instead.
|
- Removed the mockups from the project. Recommended to use tests instead.
|
||||||
- The API method `api.settings.update` has been deprecated in favor of `api.settings.extend`.
|
- The API method `api.settings.update` has been deprecated in favor of `api.settings.extend`.
|
||||||
|
66
spec/mam.js
66
spec/mam.js
@ -32,7 +32,7 @@ describe("Message Archive Management", function () {
|
|||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
`<x type="submit" xmlns="jabber:x:data">`+
|
||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>2</max><before></before></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>2</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ describe("Message Archive Management", function () {
|
|||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
`<x type="submit" xmlns="jabber:x:data">`+
|
||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>2</max><after>${message.querySelector('result').getAttribute('id')}</after></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><after>${message.querySelector('result').getAttribute('id')}</after><max>2</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
@ -165,7 +165,8 @@ describe("Message Archive Management", function () {
|
|||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
||||||
`<max>2</max><after>${last_msg_id}</after>`+
|
`<after>${last_msg_id}</after>`+
|
||||||
|
`<max>2</max>`+
|
||||||
`</set>`+
|
`</set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
@ -695,8 +696,8 @@ describe("Message Archive Management", function () {
|
|||||||
`</field>`+
|
`</field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
||||||
`<max>10</max>`+
|
|
||||||
`<after>09af3-cc343-b409f</after>`+
|
`<after>09af3-cc343-b409f</after>`+
|
||||||
|
`<max>10</max>`+
|
||||||
`</set>`+
|
`</set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
@ -725,49 +726,7 @@ describe("Message Archive Management", function () {
|
|||||||
`</field>`+
|
`</field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
||||||
`<max>10</max>`+
|
|
||||||
`<before></before>`+
|
`<before></before>`+
|
||||||
`</set>`+
|
|
||||||
`</query>`+
|
|
||||||
`</iq>`);
|
|
||||||
done();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it("accepts a _converse.RSM object for the query options",
|
|
||||||
mock.initConverse([], {}, async function (done, _converse) {
|
|
||||||
|
|
||||||
await mock.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, null, [Strophe.NS.MAM]);
|
|
||||||
let sent_stanza, IQ_id;
|
|
||||||
const sendIQ = _converse.connection.sendIQ;
|
|
||||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
|
||||||
sent_stanza = iq;
|
|
||||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
|
||||||
});
|
|
||||||
// Normally the user wouldn't manually make a _converse.RSM object
|
|
||||||
// and pass it in. However, in the callback method an RSM object is
|
|
||||||
// returned which can be reused for easy paging. This test is
|
|
||||||
// more for that usecase.
|
|
||||||
const rsm = new _converse.RSM({'max': '10'});
|
|
||||||
rsm['with'] = 'romeo@montague.lit'; // eslint-disable-line dot-notation
|
|
||||||
rsm.start = '2010-06-07T00:00:00Z';
|
|
||||||
_converse.api.archive.query(rsm);
|
|
||||||
await u.waitUntil(() => sent_stanza);
|
|
||||||
const queryid = sent_stanza.querySelector('query').getAttribute('queryid');
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toBe(
|
|
||||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query queryid="${queryid}" xmlns="urn:xmpp:mam:2">`+
|
|
||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
|
||||||
`<field type="hidden" var="FORM_TYPE">`+
|
|
||||||
`<value>urn:xmpp:mam:2</value>`+
|
|
||||||
`</field>`+
|
|
||||||
`<field var="with">`+
|
|
||||||
`<value>romeo@montague.lit</value>`+
|
|
||||||
`</field>`+
|
|
||||||
`<field var="start">`+
|
|
||||||
`<value>${dayjs(rsm.start).toISOString()}</value>`+
|
|
||||||
`</field>`+
|
|
||||||
`</x>`+
|
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm">`+
|
|
||||||
`<max>10</max>`+
|
`<max>10</max>`+
|
||||||
`</set>`+
|
`</set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
@ -850,11 +809,10 @@ describe("Message Archive Management", function () {
|
|||||||
expect(result.messages.length).toBe(2);
|
expect(result.messages.length).toBe(2);
|
||||||
expect(result.messages[0].outerHTML).toBe(msg1.nodeTree.outerHTML);
|
expect(result.messages[0].outerHTML).toBe(msg1.nodeTree.outerHTML);
|
||||||
expect(result.messages[1].outerHTML).toBe(msg2.nodeTree.outerHTML);
|
expect(result.messages[1].outerHTML).toBe(msg2.nodeTree.outerHTML);
|
||||||
expect(result.rsm['with']).toBe('romeo@capulet.lit'); // eslint-disable-line dot-notation
|
expect(result.rsm.query.max).toBe('10');
|
||||||
expect(result.rsm.max).toBe('10');
|
expect(result.rsm.result.count).toBe(16);
|
||||||
expect(result.rsm.count).toBe('16');
|
expect(result.rsm.result.first).toBe('23452-4534-1');
|
||||||
expect(result.rsm.first).toBe('23452-4534-1');
|
expect(result.rsm.result.last).toBe('09af3-cc343-b409f');
|
||||||
expect(result.rsm.last).toBe('09af3-cc343-b409f');
|
|
||||||
done()
|
done()
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@ -962,7 +920,7 @@ describe("Chatboxes", function () {
|
|||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`
|
`</iq>`
|
||||||
);
|
);
|
||||||
@ -1033,7 +991,7 @@ describe("Chatboxes", function () {
|
|||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
@ -1058,7 +1016,7 @@ describe("Chatboxes", function () {
|
|||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
`<field var="with"><value>mercutio@montague.lit</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
|
@ -458,7 +458,7 @@ describe("Groupchats", function () {
|
|||||||
`<x type="submit" xmlns="jabber:x:data">`+
|
`<x type="submit" xmlns="jabber:x:data">`+
|
||||||
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
`<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
|
||||||
`</x>`+
|
`</x>`+
|
||||||
`<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
|
`<set xmlns="http://jabber.org/protocol/rsm"><before></before><max>50</max></set>`+
|
||||||
`</query>`+
|
`</query>`+
|
||||||
`</iq>`);
|
`</iq>`);
|
||||||
|
|
||||||
|
@ -7,19 +7,15 @@
|
|||||||
import "./converse-disco";
|
import "./converse-disco";
|
||||||
import "./converse-rsm";
|
import "./converse-rsm";
|
||||||
import { _converse, api, converse } from "@converse/headless/converse-core";
|
import { _converse, api, converse } from "@converse/headless/converse-core";
|
||||||
import { intersection, pick } from 'lodash-es'
|
|
||||||
import log from "./log";
|
import log from "./log";
|
||||||
import sizzle from "sizzle";
|
import sizzle from "sizzle";
|
||||||
import st from "./utils/stanza";
|
import st from "./utils/stanza";
|
||||||
|
import { RSM } from '@converse/headless/converse-rsm';
|
||||||
|
|
||||||
const { Strophe, $iq, dayjs } = converse.env;
|
const { Strophe, $iq, dayjs } = converse.env;
|
||||||
const { NS } = Strophe;
|
const { NS } = Strophe;
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
|
|
||||||
// XEP-0313 Message Archive Management
|
|
||||||
const MAM_ATTRIBUTES = ['with', 'start', 'end'];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MUC utils object. Contains utility functions related to multi-user chat.
|
* The MUC utils object. Contains utility functions related to multi-user chat.
|
||||||
* @mixin MAMEnabledChat
|
* @mixin MAMEnabledChat
|
||||||
@ -77,7 +73,7 @@ const MAMEnabledChat = {
|
|||||||
* Fetch XEP-0313 archived messages based on the passed in criteria.
|
* Fetch XEP-0313 archived messages based on the passed in criteria.
|
||||||
* @private
|
* @private
|
||||||
* @param { Object } options
|
* @param { Object } options
|
||||||
* @param { integer } [options.max] - The maxinum number of items to return.
|
* @param { integer } [options.max] - The maximum number of items to return.
|
||||||
* Defaults to "archived_messages_page_size"
|
* Defaults to "archived_messages_page_size"
|
||||||
* @param { string } [options.after] - The XEP-0359 stanza ID of a message
|
* @param { string } [options.after] - The XEP-0359 stanza ID of a message
|
||||||
* after which messages should be returned. Implies forward paging.
|
* after which messages should be returned. Implies forward paging.
|
||||||
@ -102,20 +98,21 @@ const MAMEnabledChat = {
|
|||||||
if (!(await api.disco.supports(NS.MAM, mam_jid))) {
|
if (!(await api.disco.supports(NS.MAM, mam_jid))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const max = api.settings.get('archived_messages_page_size')
|
||||||
const query = Object.assign({
|
const query = Object.assign({
|
||||||
'groupchat': is_muc,
|
'groupchat': is_muc,
|
||||||
'max': api.settings.get('archived_messages_page_size'),
|
'max': max,
|
||||||
'with': this.get('jid'),
|
'with': this.get('jid'),
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
const result = await api.archive.query(query);
|
const result = await api.archive.query(query);
|
||||||
await this.handleMAMResult(result, query, options, page_direction);
|
await this.handleMAMResult(result, query, options, page_direction);
|
||||||
|
|
||||||
if (page_direction && result.rsm) {
|
if (page_direction && result.rsm && !result.complete) {
|
||||||
if (page_direction === 'forwards') {
|
if (page_direction === 'forwards') {
|
||||||
options = result.rsm.next(api.settings.get('archived_messages_page_size'), options.before);
|
options = result.rsm.next(max, options.before).query;
|
||||||
} else if (page_direction === 'backwards') {
|
} else if (page_direction === 'backwards') {
|
||||||
options = result.rsm.previous(api.settings.get('archived_messages_page_size'), options.after);
|
options = result.rsm.previous(max, options.after).query;
|
||||||
}
|
}
|
||||||
return this.fetchArchivedMessages(options, page_direction);
|
return this.fetchArchivedMessages(options, page_direction);
|
||||||
} else {
|
} else {
|
||||||
@ -253,36 +250,38 @@ converse.plugins.add('converse-mam', {
|
|||||||
* option in the configuration settings section, which you'll
|
* option in the configuration settings section, which you'll
|
||||||
* usually want to use in conjunction with this API.
|
* usually want to use in conjunction with this API.
|
||||||
*
|
*
|
||||||
* @namespace api.archive
|
* @namespace _converse.api.archive
|
||||||
* @memberOf api
|
* @memberOf _converse.api
|
||||||
*/
|
*/
|
||||||
'archive': {
|
archive: {
|
||||||
|
/**
|
||||||
|
* @typedef { module:converse-rsm~RSMQueryParameters } MAMFilterParameters
|
||||||
|
* Filter parameters which can be used to filter a MAM XEP-0313 archive
|
||||||
|
* @property { String } [end] - A date string in ISO-8601 format, before which messages should be returned. Implies backward paging.
|
||||||
|
* @property { String } [start] - A date string in ISO-8601 format, after which messages should be returned. Implies forward paging.
|
||||||
|
* @property { String } [with] - A JID against which to match messages, according to either their `to` or `from` attributes.
|
||||||
|
* An item in a MUC archive matches if the publisher of the item matches the JID.
|
||||||
|
* If `with` is omitted, all messages that match the rest of the query will be returned, regardless of to/from
|
||||||
|
* addresses of each message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options that can be passed in to the { @link _converse.api.archive.query } method
|
||||||
|
* @typedef { module:converse-mam~MAMFilterParameters } ArchiveQueryOptions
|
||||||
|
* @property { Boolean } [groupchat=false] - Whether the MAM archive is for a groupchat.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query for archived messages.
|
* Query for archived messages.
|
||||||
*
|
*
|
||||||
* The options parameter can also be an instance of
|
* The options parameter can also be an instance of
|
||||||
* _converse.RSM to enable easy querying between results pages.
|
* RSM to enable easy querying between results pages.
|
||||||
*
|
*
|
||||||
* @method api.archive.query
|
* @method _converse.api.archive.query
|
||||||
* @param {(Object|_converse.RSM)} options Query parameters, either
|
* @param { module:converse-mam~ArchiveQueryOptions } options - An object containing query parameters
|
||||||
* MAM-specific or also for Result Set Management.
|
|
||||||
* Can be either an object or an instance of _converse.RSM.
|
|
||||||
* Valid query parameters are:
|
|
||||||
* * `with`
|
|
||||||
* * `start`
|
|
||||||
* * `end`
|
|
||||||
* * `first`
|
|
||||||
* * `last`
|
|
||||||
* * `after`
|
|
||||||
* * `before`
|
|
||||||
* * `index`
|
|
||||||
* * `count`
|
|
||||||
* * `groupchat`
|
|
||||||
* @throws {Error} An error is thrown if the XMPP server responds with an error.
|
* @throws {Error} An error is thrown if the XMPP server responds with an error.
|
||||||
* @returns { (Promise<Object> | _converse.TimeoutError) } A promise which resolves
|
* @returns { Promise<module:converse-mam~MAMQueryResult> } A promise which resolves
|
||||||
* to an object which will have keys `messages` and `rsm` which contains a _converse.RSM
|
* to a { @link module:converse-mam~MAMQueryResult } object.
|
||||||
* object on which "next" or "previous" can be called before passing it in again
|
|
||||||
* to this method, to get the next or previous page in the result set.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Requesting all archived messages
|
* // Requesting all archived messages
|
||||||
@ -369,7 +368,7 @@ converse.plugins.add('converse-mam', {
|
|||||||
* // repeatedly make a further query to fetch the next batch of messages.
|
* // repeatedly make a further query to fetch the next batch of messages.
|
||||||
* //
|
* //
|
||||||
* // To simplify this usecase for you, the callback method receives not only an array
|
* // To simplify this usecase for you, the callback method receives not only an array
|
||||||
* // with the returned archived messages, but also a special _converse.RSM (*Result Set Management*)
|
* // with the returned archived messages, but also a special RSM (*Result Set Management*)
|
||||||
* // object which contains the query parameters you passed in, as well
|
* // object which contains the query parameters you passed in, as well
|
||||||
* // as two utility methods `next`, and `previous`.
|
* // as two utility methods `next`, and `previous`.
|
||||||
* //
|
* //
|
||||||
@ -378,18 +377,19 @@ converse.plugins.add('converse-mam', {
|
|||||||
* // archived messages. Please note, when calling these methods, pass in an integer
|
* // archived messages. Please note, when calling these methods, pass in an integer
|
||||||
* // to limit your results.
|
* // to limit your results.
|
||||||
*
|
*
|
||||||
|
* const options = {'with': 'john@doe.net', 'max':10};
|
||||||
* let result;
|
* let result;
|
||||||
* try {
|
* try {
|
||||||
* result = await api.archive.query({'with': 'john@doe.net', 'max':10});
|
* result = await api.archive.query(options);
|
||||||
* } catch (e) {
|
* } catch (e) {
|
||||||
* // The query was not successful
|
* // The query was not successful
|
||||||
* }
|
* }
|
||||||
* // Do something with the messages, like showing them in your webpage.
|
* // Do something with the messages, like showing them in your webpage.
|
||||||
* result.messages.forEach(m => this.showMessage(m));
|
* result.messages.forEach(m => this.showMessage(m));
|
||||||
*
|
*
|
||||||
* while (result.rsm) {
|
* while (!result.complete) {
|
||||||
* try {
|
* try {
|
||||||
* result = await api.archive.query(rsm.next(10));
|
* result = await api.archive.query(Object.assign(options, rsm.next(10).query));
|
||||||
* } catch (e) {
|
* } catch (e) {
|
||||||
* // The query was not successful
|
* // The query was not successful
|
||||||
* }
|
* }
|
||||||
@ -407,8 +407,9 @@ converse.plugins.add('converse-mam', {
|
|||||||
* // message, pass in the `before` parameter with an empty string value `''`.
|
* // message, pass in the `before` parameter with an empty string value `''`.
|
||||||
*
|
*
|
||||||
* let result;
|
* let result;
|
||||||
|
* const options = {'before': '', 'max':5};
|
||||||
* try {
|
* try {
|
||||||
* result = await api.archive.query({'before': '', 'max':5});
|
* result = await api.archive.query(options);
|
||||||
* } catch (e) {
|
* } catch (e) {
|
||||||
* // The query was not successful
|
* // The query was not successful
|
||||||
* }
|
* }
|
||||||
@ -417,7 +418,7 @@ converse.plugins.add('converse-mam', {
|
|||||||
*
|
*
|
||||||
* // Now we query again, to get the previous batch.
|
* // Now we query again, to get the previous batch.
|
||||||
* try {
|
* try {
|
||||||
* result = await api.archive.query(rsm.previous(5););
|
* result = await api.archive.query(Object.assign(options, rsm.previous(5).query));
|
||||||
* } catch (e) {
|
* } catch (e) {
|
||||||
* // The query was not successful
|
* // The query was not successful
|
||||||
* }
|
* }
|
||||||
@ -468,10 +469,9 @@ converse.plugins.add('converse-mam', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
stanza.up();
|
stanza.up();
|
||||||
if (options instanceof _converse.RSM) {
|
const rsm = new RSM(options);
|
||||||
stanza.cnode(options.toXML());
|
if (Object.keys(rsm.query).length) {
|
||||||
} else if (intersection(_converse.RSM_ATTRIBUTES, Object.keys(options)).length) {
|
stanza.cnode(rsm.toXML());
|
||||||
stanza.cnode(new _converse.RSM(options).toXML());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,28 +498,40 @@ converse.plugins.add('converse-mam', {
|
|||||||
let error;
|
let error;
|
||||||
const iq_result = await api.sendIQ(stanza, api.settings.get('message_archiving_timeout'), false)
|
const iq_result = await api.sendIQ(stanza, api.settings.get('message_archiving_timeout'), false)
|
||||||
if (iq_result === null) {
|
if (iq_result === null) {
|
||||||
const err_msg = "Timeout while trying to fetch archived messages.";
|
const { __ } = _converse;
|
||||||
|
const err_msg = __("Timeout while trying to fetch archived messages.");
|
||||||
log.error(err_msg);
|
log.error(err_msg);
|
||||||
error = new _converse.TimeoutError(err_msg);
|
error = new _converse.TimeoutError(err_msg);
|
||||||
return { messages, error };
|
return { messages, error };
|
||||||
|
|
||||||
} else if (u.isErrorStanza(iq_result)) {
|
} else if (u.isErrorStanza(iq_result)) {
|
||||||
log.error("Error stanza received while trying to fetch archived messages");
|
const { __ } = _converse;
|
||||||
|
const err_msg = __('An error occurred while querying for archived messages.');
|
||||||
|
log.error(err_msg);
|
||||||
log.error(iq_result);
|
log.error(iq_result);
|
||||||
return { messages };
|
error = new Error(err_msg);
|
||||||
|
return { messages, error };
|
||||||
}
|
}
|
||||||
_converse.connection.deleteHandler(message_handler);
|
_converse.connection.deleteHandler(message_handler);
|
||||||
|
|
||||||
let rsm;
|
let rsm;
|
||||||
const fin = iq_result && sizzle(`fin[xmlns="${NS.MAM}"]`, iq_result).pop();
|
const fin = iq_result && sizzle(`fin[xmlns="${NS.MAM}"]`, iq_result).pop();
|
||||||
if (fin && [null, 'false'].includes(fin.getAttribute('complete'))) {
|
const complete = fin?.getAttribute('complete') === 'true'
|
||||||
const set = sizzle(`set[xmlns="${NS.RSM}"]`, fin).pop();
|
const set = sizzle(`set[xmlns="${NS.RSM}"]`, fin).pop();
|
||||||
if (set) {
|
if (set) {
|
||||||
rsm = new _converse.RSM({'xml': set});
|
rsm = new RSM({...options, 'xml': set});
|
||||||
Object.assign(rsm, Object.assign(pick(options, [...MAM_ATTRIBUTES, ..._converse.RSM_ATTRIBUTES]), rsm));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return { messages, rsm, error };
|
/**
|
||||||
|
* @typedef { Object } MAMQueryResult
|
||||||
|
* @property { Array } messages
|
||||||
|
* @property { RSM } [rsm] - An instance of { @link RSM }.
|
||||||
|
* You can call `next()` or `previous()` on this instance,
|
||||||
|
* to get the RSM query parameters for the next or previous
|
||||||
|
* page in the result set.
|
||||||
|
* @property { Boolean } complete
|
||||||
|
* @property { Error } [error]
|
||||||
|
*/
|
||||||
|
return { messages, rsm, complete };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -6,64 +6,102 @@
|
|||||||
* Some code taken from the Strophe RSM plugin, licensed under the MIT License
|
* Some code taken from the Strophe RSM plugin, licensed under the MIT License
|
||||||
* Copyright 2006-2017 Strophe (https://github.com/strophe/strophejs)
|
* Copyright 2006-2017 Strophe (https://github.com/strophe/strophejs)
|
||||||
*/
|
*/
|
||||||
import { converse } from "./converse-core";
|
import { _converse, converse } from "./converse-core";
|
||||||
|
import { pick } from 'lodash-es'
|
||||||
|
|
||||||
const { Strophe, $build } = converse.env;
|
const { Strophe, $build } = converse.env;
|
||||||
|
|
||||||
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
||||||
|
|
||||||
|
|
||||||
converse.plugins.add('converse-rsm', {
|
/**
|
||||||
initialize () {
|
* @typedef { Object } RSMQueryParameters
|
||||||
const { _converse } = this;
|
* [XEP-0059 RSM](https://xmpp.org/extensions/xep-0059.html) Attributes that can be used to filter query results
|
||||||
const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'count'];
|
* @property { String } [after] - The XEP-0359 stanza ID of a message after which messages should be returned. Implies forward paging.
|
||||||
_converse.RSM_ATTRIBUTES = RSM_ATTRIBUTES;
|
* @property { String } [before] - The XEP-0359 stanza ID of a message before which messages should be returned. Implies backward paging.
|
||||||
|
* @property { Integer } [index=0] - The index of the results page to return.
|
||||||
|
* @property { Integer } [max] - The maximum number of items to return.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const RSM_QUERY_PARAMETERS = ['after', 'before', 'index', 'max'];
|
||||||
|
|
||||||
|
const toNumber = v => Number(v);
|
||||||
|
const toString = v => v.toString();
|
||||||
|
|
||||||
|
export const RSM_TYPES = {
|
||||||
|
'after': toString,
|
||||||
|
'before': toString,
|
||||||
|
'count': toNumber,
|
||||||
|
'first': toString,
|
||||||
|
'index': toNumber,
|
||||||
|
'last': toString,
|
||||||
|
'max': toNumber
|
||||||
|
};
|
||||||
|
|
||||||
|
const isUndefined = (x) => typeof x === 'undefined';
|
||||||
|
|
||||||
|
|
||||||
class RSM {
|
// This array contains both query attributes and response attributes
|
||||||
constructor (options) {
|
export const RSM_ATTRIBUTES = Object.keys(RSM_TYPES);
|
||||||
if (typeof options.xml != 'undefined') {
|
|
||||||
this.fromXMLElement(options.xml);
|
|
||||||
} else {
|
|
||||||
for (let ii = 0; ii < RSM_ATTRIBUTES.length; ii++) {
|
|
||||||
const attrib = RSM_ATTRIBUTES[ii];
|
|
||||||
this[attrib] = options[attrib];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toXML () {
|
|
||||||
let xml = $build('set', {xmlns: Strophe.NS.RSM});
|
|
||||||
for (let ii = 0; ii < RSM_ATTRIBUTES.length; ii++) {
|
|
||||||
const attrib = RSM_ATTRIBUTES[ii];
|
|
||||||
if (typeof this[attrib] != 'undefined') {
|
|
||||||
xml = xml.c(attrib).t(this[attrib].toString()).up();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return xml.tree();
|
|
||||||
}
|
|
||||||
|
|
||||||
next (max, before) {
|
/**
|
||||||
return new RSM({max: max, after: this.last, before});
|
* Instances of this class are used to page through query results according to XEP-0059 Result Set Management
|
||||||
}
|
* @class RSM
|
||||||
|
*/
|
||||||
|
export class RSM {
|
||||||
|
|
||||||
previous (max, after) {
|
static getQueryParameters (options={}) {
|
||||||
return new RSM({max: max, before: this.first, after});
|
return pick(options, RSM_QUERY_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
fromXMLElement (xmlElement) {
|
static parseXMLResult (set) {
|
||||||
for (var ii = 0; ii < RSM_ATTRIBUTES.length; ii++) {
|
const result = {};
|
||||||
const attrib = RSM_ATTRIBUTES[ii];
|
for (var i = 0; i < RSM_ATTRIBUTES.length; i++) {
|
||||||
const elem = xmlElement.getElementsByTagName(attrib)[0];
|
const attr = RSM_ATTRIBUTES[i];
|
||||||
if (typeof elem != 'undefined' && elem !== null) {
|
const elem = set.getElementsByTagName(attr)[0];
|
||||||
this[attrib] = Strophe.getText(elem);
|
if (!isUndefined(elem) && elem !== null) {
|
||||||
if (attrib == 'first') {
|
result[attr] = RSM_TYPES[attr](Strophe.getText(elem));
|
||||||
this.index = elem.getAttribute('index');
|
if (attr == 'first') {
|
||||||
}
|
result.index = RSM_TYPES['index'](elem.getAttribute('index'));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_converse.RSM = RSM;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Create a new RSM instance
|
||||||
|
* @param { Object } options - Configuration options
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor (options={}) {
|
||||||
|
this.query = RSM.getQueryParameters(options);
|
||||||
|
this.result = options.xml ? RSM.parseXMLResult(options.xml) : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a `<set>` XML element that confirms to XEP-0059 Result Set Management.
|
||||||
|
* The element is constructed based on the { @link module:converse-rsm~RSMQueryParameters }
|
||||||
|
* that are set on this RSM instance.
|
||||||
|
* @returns { XMLElement }
|
||||||
|
*/
|
||||||
|
toXML () {
|
||||||
|
const xml = $build('set', {xmlns: Strophe.NS.RSM});
|
||||||
|
const reducer = (xml, a) => !isUndefined(this.query[a]) ? xml.c(a).t((this.query[a] || '').toString()).up() : xml;
|
||||||
|
return RSM_QUERY_PARAMETERS.reduce(reducer, xml).tree();
|
||||||
|
}
|
||||||
|
|
||||||
|
next (max, before) {
|
||||||
|
const options = Object.assign({}, this.query, { after: this.result.last, before, max });
|
||||||
|
return new RSM(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous (max, after) {
|
||||||
|
const options = Object.assign({}, this.query, { after, before: this.result.first, max });
|
||||||
|
return new RSM(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_converse.RSM_ATTRIBUTES = RSM_ATTRIBUTES;
|
||||||
|
_converse.RSM = RSM;
|
||||||
|
@ -16,7 +16,6 @@ import "./converse-muc"; // XEP-0045 Multi-user chat
|
|||||||
import "./converse-ping"; // XEP-0199 XMPP Ping
|
import "./converse-ping"; // XEP-0199 XMPP Ping
|
||||||
import "./converse-pubsub"; // XEP-0060 Pubsub
|
import "./converse-pubsub"; // XEP-0060 Pubsub
|
||||||
import "./converse-roster"; // RFC-6121 Contacts Roster
|
import "./converse-roster"; // RFC-6121 Contacts Roster
|
||||||
import "./converse-rsm"; // XEP-0059 Result Set management
|
|
||||||
import "./converse-smacks"; // XEP-0198 Stream Management
|
import "./converse-smacks"; // XEP-0198 Stream Management
|
||||||
import "./converse-status"; // XEP-0199 XMPP Ping
|
import "./converse-status"; // XEP-0199 XMPP Ping
|
||||||
import "./converse-vcard"; // XEP-0054 VCard-temp
|
import "./converse-vcard"; // XEP-0054 VCard-temp
|
||||||
|
Loading…
Reference in New Issue
Block a user