Răsfoiți Sursa

converse-roster: Move functions to utils

JC Brand 4 ani în urmă
părinte
comite
629f382642

+ 2 - 1
src/headless/plugins/roster/contact.js

@@ -1,6 +1,7 @@
 import { Model } from '@converse/skeletor/src/model.js';
 import { _converse, api, converse } from "@converse/headless/core";
 import { getOpenPromise } from '@converse/openpromise';
+import { rejectPresenceSubscription } from './utils.js';
 
 const { Strophe, $iq, $pres } = converse.env;
 
@@ -147,7 +148,7 @@ const RosterContact = Model.extend({
      * @param { String } message - Optional message to send to the person being unauthorized
      */
     unauthorize (message) {
-        _converse.rejectPresenceSubscription(this.get('jid'), message);
+        rejectPresenceSubscription(this.get('jid'), message);
         return this;
     },
 

+ 3 - 3
src/headless/plugins/roster/contacts.js

@@ -6,9 +6,9 @@ import { Model } from "@converse/skeletor/src/model";
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
 import { initStorage } from '@converse/headless/shared/utils.js';
+import { rejectPresenceSubscription } from './utils.js';
 
-const { Strophe, $iq, sizzle } = converse.env;
-const u = converse.env.utils;
+const { Strophe, $iq, sizzle, u } = converse.env;
 
 
 const RosterContacts = Collection.extend({
@@ -355,7 +355,7 @@ const RosterContacts = Collection.extend({
             contact = this.get(bare_jid);
 
         if (!api.settings.get('allow_contact_requests')) {
-            _converse.rejectPresenceSubscription(
+            rejectPresenceSubscription(
                 jid,
                 __("This client does not allow presence subscriptions")
             );

+ 19 - 169
src/headless/plugins/roster/index.js

@@ -2,206 +2,56 @@
  * @copyright The Converse.js contributors
  * @license Mozilla Public License (MPLv2)
  */
-import "@converse/headless/plugins/status";
+import '@converse/headless/plugins/status';
 import RosterContact from './contact.js';
 import RosterContacts from './contacts.js';
-import invoke from 'lodash-es/invoke';
-import log from "@converse/headless/log";
 import roster_api from './api.js';
 import { Presence, Presences } from './presence.js';
 import { __ } from 'i18n';
-import { _converse, api, converse } from "@converse/headless/core";
-import { clearPresences, initRoster, updateUnreadCounter } from './utils.js';
-import { initStorage } from '@converse/headless/shared/utils.js';
-
-const { $pres } = converse.env;
+import { _converse, api, converse } from '@converse/headless/core';
+import {
+    onChatBoxesInitialized,
+    onClearSession,
+    onPresencesInitialized,
+    onRosterContactsFetched,
+    onStatusInitialized,
+    unregisterPresenceHandler,
+} from './utils.js';
 
 
 converse.plugins.add('converse-roster', {
-
     dependencies: ['converse-status'],
 
     initialize () {
-        /* The initialize function gets called as soon as the plugin is
-         * loaded by converse.js's plugin machinery.
-         */
         api.settings.extend({
             'allow_contact_requests': true,
             'auto_subscribe': false,
-            'synchronize_availability': true,
+            'synchronize_availability': true
         });
 
-        api.promises.add([
-            'cachedRoster',
-            'roster',
-            'rosterContactsFetched',
-            'rosterInitialized',
-        ]);
+        api.promises.add(['cachedRoster', 'roster', 'rosterContactsFetched', 'rosterInitialized']);
 
         // API methods only available to plugins
         Object.assign(_converse.api, roster_api);
 
-        _converse.HEADER_CURRENT_CONTACTS =  __('My contacts');
+        _converse.HEADER_CURRENT_CONTACTS = __('My contacts');
         _converse.HEADER_PENDING_CONTACTS = __('Pending contacts');
         _converse.HEADER_REQUESTING_CONTACTS = __('Contact requests');
         _converse.HEADER_UNGROUPED = __('Ungrouped');
         _converse.HEADER_UNREAD = __('New messages');
 
-
-        _converse.registerPresenceHandler = function () {
-            _converse.unregisterPresenceHandler();
-            _converse.presence_ref = _converse.connection.addHandler(presence => {
-                    _converse.roster.presenceHandler(presence);
-                    return true;
-                }, null, 'presence', null);
-        };
-
-
-        /**
-         * Reject or cancel another user's subscription to our presence updates.
-         * @method rejectPresenceSubscription
-         * @private
-         * @memberOf _converse
-         * @param { String } jid - The Jabber ID of the user whose subscription is being canceled
-         * @param { String } message - An optional message to the user
-         */
-        _converse.rejectPresenceSubscription = function (jid, message) {
-            const pres = $pres({to: jid, type: "unsubscribed"});
-            if (message && message !== "") { pres.c("status").t(message); }
-            api.send(pres);
-        };
-
-
-        _converse.sendInitialPresence = function () {
-            if (_converse.send_initial_presence) {
-                api.user.presence.send();
-            }
-        };
-
-
-        /**
-         * Fetch all the roster groups, and then the roster contacts.
-         * Emit an event after fetching is done in each case.
-         * @private
-         * @method _converse.populateRoster
-         * @param { Bool } ignore_cache - If set to to true, the local cache
-         *      will be ignored it's guaranteed that the XMPP server
-         *      will be queried for the roster.
-         */
-        _converse.populateRoster = async function (ignore_cache=false) {
-            if (ignore_cache) {
-                _converse.send_initial_presence = true;
-            }
-            try {
-                await _converse.roster.fetchRosterContacts();
-                api.trigger('rosterContactsFetched');
-            } catch (reason) {
-                log.error(reason);
-            } finally {
-                _converse.sendInitialPresence();
-            }
-        };
-
         _converse.Presence = Presence;
         _converse.Presences = Presences;
         _converse.RosterContact = RosterContact;
         _converse.RosterContacts = RosterContacts;
 
-        _converse.unregisterPresenceHandler = function () {
-            if (_converse.presence_ref !== undefined) {
-                _converse.connection.deleteHandler(_converse.presence_ref);
-                delete _converse.presence_ref;
-            }
-        };
-
-
-        /******************** Event Handlers ********************/
-        api.listen.on('chatBoxesInitialized', () => {
-            _converse.chatboxes.on('change:num_unread', updateUnreadCounter);
-
-            _converse.chatboxes.on('add', chatbox => {
-                if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
-                    chatbox.setRosterContact(chatbox.get('jid'));
-                }
-            });
-        });
-
-        api.listen.on('beforeTearDown', () => _converse.unregisterPresenceHandler());
-
-        api.waitUntil('rosterContactsFetched').then(() => {
-            _converse.roster.on('add', (contact) => {
-                /* When a new contact is added, check if we already have a
-                 * chatbox open for it, and if so attach it to the chatbox.
-                 */
-                const chatbox = _converse.chatboxes.findWhere({'jid': contact.get('jid')});
-                if (chatbox) {
-                    chatbox.setRosterContact(contact.get('jid'));
-                }
-            });
-        });
-
-
+        api.listen.on('beforeTearDown', () => unregisterPresenceHandler());
+        api.listen.on('chatBoxesInitialized', onChatBoxesInitialized);
+        api.listen.on('clearSession', onClearSession);
+        api.listen.on('presencesInitialized', onPresencesInitialized);
+        api.listen.on('statusInitialized', onStatusInitialized);
         api.listen.on('streamResumptionFailed', () => _converse.session.set('roster_cached', false));
 
-        api.listen.on('clearSession', async () => {
-            await clearPresences();
-            if (_converse.shouldClearCache()) {
-                if (_converse.rostergroups) {
-                    await _converse.rostergroups.clearStore();
-                    delete _converse.rostergroups;
-                }
-                if (_converse.roster) {
-                    invoke(_converse, 'roster.data.destroy');
-                    await _converse.roster.clearStore();
-                    delete _converse.roster;
-                }
-            }
-        });
-
-
-        api.listen.on('statusInitialized', async reconnecting => {
-            if (reconnecting) {
-                // When reconnecting and not resuming a previous session,
-                // we clear all cached presence data, since it might be stale
-                // and we'll receive new presence updates
-                !_converse.connection.hasResumed() && await clearPresences();
-            } else {
-                _converse.presences = new _converse.Presences();
-                const id = `converse.presences-${_converse.bare_jid}`;
-                initStorage(_converse.presences, id, 'session');
-                // We might be continuing an existing session, so we fetch
-                // cached presence data.
-                _converse.presences.fetch();
-            }
-            /**
-             * Triggered once the _converse.Presences collection has been
-             * initialized and its cached data fetched.
-             * Returns a boolean indicating whether this event has fired due to
-             * Converse having reconnected.
-             * @event _converse#presencesInitialized
-             * @type { bool }
-             * @example _converse.api.listen.on('presencesInitialized', reconnecting => { ... });
-             */
-            api.trigger('presencesInitialized', reconnecting);
-        });
-
-
-        api.listen.on('presencesInitialized', async (reconnecting) => {
-            if (reconnecting) {
-                /**
-                 * Similar to `rosterInitialized`, but instead pertaining to reconnection.
-                 * This event indicates that the roster and its groups are now again
-                 * available after Converse.js has reconnected.
-                 * @event _converse#rosterReadyAfterReconnection
-                 * @example _converse.api.listen.on('rosterReadyAfterReconnection', () => { ... });
-                 */
-                api.trigger('rosterReadyAfterReconnection');
-            } else {
-                await initRoster();
-            }
-            _converse.roster.onConnected();
-            _converse.registerPresenceHandler();
-            _converse.populateRoster(!_converse.connection.restored);
-        });
+        api.waitUntil('rosterContactsFetched').then(onRosterContactsFetched);
     }
 });

+ 157 - 4
src/headless/plugins/roster/utils.js

@@ -1,9 +1,12 @@
-import { _converse, api } from "@converse/headless/core";
+import log from "@converse/headless/log";
 import { Model } from '@converse/skeletor/src/model.js';
+import { _converse, api, converse } from "@converse/headless/core";
 import { initStorage } from '@converse/headless/shared/utils.js';
 
+const { $pres } = converse.env;
 
-export async function initRoster () {
+
+async function initRoster () {
     // Initialize the Bakcbone collections that represent the contats
     // roster and the roster groups.
     await api.waitUntil('VCardsInitialized');
@@ -28,19 +31,169 @@ export async function initRoster () {
 }
 
 
-export function updateUnreadCounter (chatbox) {
+/**
+ * Fetch all the roster groups, and then the roster contacts.
+ * Emit an event after fetching is done in each case.
+ * @private
+ * @param { Bool } ignore_cache - If set to to true, the local cache
+ *      will be ignored it's guaranteed that the XMPP server
+ *      will be queried for the roster.
+ */
+async function populateRoster (ignore_cache=false) {
+    if (ignore_cache) {
+        _converse.send_initial_presence = true;
+    }
+    try {
+        await _converse.roster.fetchRosterContacts();
+        api.trigger('rosterContactsFetched');
+    } catch (reason) {
+        log.error(reason);
+    } finally {
+        _converse.send_initial_presence && api.user.presence.send();
+    }
+}
+
+
+function updateUnreadCounter (chatbox) {
     const contact = _converse.roster && _converse.roster.findWhere({'jid': chatbox.get('jid')});
     if (contact !== undefined) {
         contact.save({'num_unread': chatbox.get('num_unread')});
     }
 }
 
+function registerPresenceHandler () {
+    unregisterPresenceHandler();
+    _converse.presence_ref = _converse.connection.addHandler(presence => {
+            _converse.roster.presenceHandler(presence);
+            return true;
+        }, null, 'presence', null);
+}
+
+export function unregisterPresenceHandler () {
+    if (_converse.presence_ref !== undefined) {
+        _converse.connection.deleteHandler(_converse.presence_ref);
+        delete _converse.presence_ref;
+    }
+}
 
-export async function clearPresences () {
+async function clearPresences () {
     await _converse.presences?.clearStore();
 }
 
 
+/**
+ * Roster specific event handler for the clearSession event
+ */
+export async function onClearSession () {
+    await clearPresences();
+    if (_converse.shouldClearCache()) {
+        if (_converse.rostergroups) {
+            await _converse.rostergroups.clearStore();
+            delete _converse.rostergroups;
+        }
+        if (_converse.roster) {
+            _converse.roster.data?.destroy();
+            await _converse.roster.clearStore();
+            delete _converse.roster;
+        }
+    }
+}
+
+
+/**
+ * Roster specific event handler for the presencesInitialized event
+ * @param { Boolean } reconnecting
+ */
+export async function onPresencesInitialized (reconnecting) {
+    if (reconnecting) {
+        /**
+         * Similar to `rosterInitialized`, but instead pertaining to reconnection.
+         * This event indicates that the roster and its groups are now again
+         * available after Converse.js has reconnected.
+         * @event _converse#rosterReadyAfterReconnection
+         * @example _converse.api.listen.on('rosterReadyAfterReconnection', () => { ... });
+         */
+        api.trigger('rosterReadyAfterReconnection');
+    } else {
+        await initRoster();
+    }
+    _converse.roster.onConnected();
+    registerPresenceHandler();
+    populateRoster(!_converse.connection.restored);
+}
+
+
+/**
+ * Roster specific event handler for the statusInitialized event
+ * @param { Boolean } reconnecting
+ */
+export async function onStatusInitialized (reconnecting) {
+     if (reconnecting) {
+         // When reconnecting and not resuming a previous session,
+         // we clear all cached presence data, since it might be stale
+         // and we'll receive new presence updates
+         !_converse.connection.hasResumed() && (await clearPresences());
+     } else {
+         _converse.presences = new _converse.Presences();
+         const id = `converse.presences-${_converse.bare_jid}`;
+         initStorage(_converse.presences, id, 'session');
+         // We might be continuing an existing session, so we fetch
+         // cached presence data.
+         _converse.presences.fetch();
+     }
+     /**
+      * Triggered once the _converse.Presences collection has been
+      * initialized and its cached data fetched.
+      * Returns a boolean indicating whether this event has fired due to
+      * Converse having reconnected.
+      * @event _converse#presencesInitialized
+      * @type { bool }
+      * @example _converse.api.listen.on('presencesInitialized', reconnecting => { ... });
+      */
+     api.trigger('presencesInitialized', reconnecting);
+}
+
+
+/**
+ * Roster specific event handler for the chatBoxesInitialized event
+ */
+export function onChatBoxesInitialized () {
+    _converse.chatboxes.on('change:num_unread', updateUnreadCounter);
+
+    _converse.chatboxes.on('add', chatbox => {
+        if (chatbox.get('type') === _converse.PRIVATE_CHAT_TYPE) {
+            chatbox.setRosterContact(chatbox.get('jid'));
+        }
+    });
+}
+
+
+/**
+ * Roster specific handler for the rosterContactsFetched promise
+ */
+export function onRosterContactsFetched () {
+    _converse.roster.on('add', contact => {
+        // When a new contact is added, check if we already have a
+        // chatbox open for it, and if so attach it to the chatbox.
+        const chatbox = _converse.chatboxes.findWhere({ 'jid': contact.get('jid') });
+        chatbox?.setRosterContact(contact.get('jid'));
+    });
+}
+
+
+/**
+ * Reject or cancel another user's subscription to our presence updates.
+ * @function rejectPresenceSubscription
+ * @param { String } jid - The Jabber ID of the user whose subscription is being canceled
+ * @param { String } message - An optional message to the user
+ */
+export function rejectPresenceSubscription (jid, message) {
+    const pres = $pres({to: jid, type: "unsubscribed"});
+    if (message && message !== "") { pres.c("status").t(message); }
+    api.send(pres);
+}
+
+
 export function contactsComparator (contact1, contact2) {
     const status1 = contact1.presence.get('show') || 'offline';
     const status2 = contact2.presence.get('show') || 'offline';

+ 7 - 2
src/plugins/bookmark-views/tests/bookmarks.js

@@ -18,9 +18,14 @@ describe("A chat room", function () {
         const { u, $iq } = converse.env;
         const nick = 'JC';
         const muc_jid = 'theplay@conference.shakespeare.lit';
-        await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
-
+        await mock.openChatRoom(_converse, 'theplay', 'conference.shakespeare.lit', 'JC');
+        await mock.getRoomFeatures(_converse, muc_jid, []);
+        await mock.waitForReservedNick(_converse, muc_jid, nick);
+        await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
         const view = _converse.chatboxviews.get(muc_jid);
+        await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
+        await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
+
         await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
         const toggle = view.querySelector('.toggle-bookmark');
         expect(toggle.title).toBe('Bookmark this groupchat');