Group MUC utility methods in muc_utils object

as opposed to having them in the `u` object
This commit is contained in:
JC Brand 2019-11-07 09:08:13 +01:00
parent 8523cae8d0
commit e915321e33
3 changed files with 107 additions and 110 deletions

View File

@ -4421,25 +4421,26 @@
var remove_absentees = false;
var new_list = [];
var old_list = [];
var delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
const muc_utils = converse.env.muc_utils;
var delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(0);
new_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
old_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(0);
// When remove_absentees is false, then affiliations in the old
// list which are not in the new one won't be removed.
old_list = [{'jid': 'oldhag666@shakespeare.lit', 'affiliation': 'owner'},
{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(0);
// With exclude_existing set to false, any changed affiliations
// will be included in the delta (i.e. existing affiliations are included in the comparison).
old_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'owner'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(1);
expect(delta[0].jid).toBe('wiccarocks@shakespeare.lit');
expect(delta[0].affiliation).toBe('member');
@ -4449,12 +4450,12 @@
remove_absentees = true;
old_list = [{'jid': 'oldhag666@shakespeare.lit', 'affiliation': 'owner'},
{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'member'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(1);
expect(delta[0].jid).toBe('oldhag666@shakespeare.lit');
expect(delta[0].affiliation).toBe('none');
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, [], old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, [], old_list);
expect(delta.length).toBe(2);
expect(delta[0].jid).toBe('oldhag666@shakespeare.lit');
expect(delta[0].affiliation).toBe('none');
@ -4465,11 +4466,11 @@
// affiliation, we set 'exclude_existing' to true
exclude_existing = true;
old_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'owner'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(0);
old_list = [{'jid': 'wiccarocks@shakespeare.lit', 'affiliation': 'admin'}];
delta = u.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
delta = muc_utils.computeAffiliationsDelta(exclude_existing, remove_absentees, new_list, old_list);
expect(delta.length).toBe(0);
done();
}));

View File

@ -11,10 +11,10 @@
*/
import "./converse-disco";
import "./converse-emoji";
import "./utils/muc";
import { clone, get, intersection, invoke, isElement, isObject, isString, uniq, zipObject } from "lodash";
import converse from "./converse-core";
import log from "./log";
import muc_utils from "./utils/muc";
import stanza_utils from "./utils/stanza";
import u from "./utils/form";
@ -1121,7 +1121,7 @@ converse.plugins.add('converse-muc', {
log.warn(result);
return err;
}
return u.parseMemberListIQ(result).filter(p => p);
return muc_utils.parseMemberListIQ(result).filter(p => p);
},
/**
@ -1141,7 +1141,7 @@ converse.plugins.add('converse-muc', {
const all_affiliations = ['member', 'admin', 'owner'];
const aff_lists = await Promise.all(all_affiliations.map(a => this.getAffiliationList(a)));
const old_members = aff_lists.reduce((acc, val) => (u.isErrorObject(val) ? acc: [...val, ...acc]), []);
await this.setAffiliations(u.computeAffiliationsDelta(true, false, members, old_members));
await this.setAffiliations(muc_utils.computeAffiliationsDelta(true, false, members, old_members));
if (_converse.muc_fetch_members) {
return this.occupants.fetchMembers();
}
@ -2121,6 +2121,8 @@ converse.plugins.add('converse-muc', {
/************************ BEGIN API ************************/
converse.env.muc_utils = muc_utils;
// We extend the default converse.js API to add methods specific to MUC groupchats.
Object.assign(_converse.api, {
/**

View File

@ -6,110 +6,104 @@
// Copyright (c) 2013-2019, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2)
//
import { difference, indexOf } from "lodash";
import converse from "@converse/headless/converse-core";
import u from "./core";
const { Strophe, sizzle, _ } = converse.env;
const { Strophe, sizzle } = converse.env;
/**
* Given two lists of objects with 'jid', 'affiliation' and
* 'reason' properties, return a new list containing
* those objects that are new, changed or removed
* (depending on the 'remove_absentees' boolean).
*
* The affiliations for new and changed members stay the
* same, for removed members, the affiliation is set to 'none'.
*
* The 'reason' property is not taken into account when
* comparing whether affiliations have been changed.
* @private
* @method u#computeAffiliationsDelta
* @param { boolean } exclude_existing - Indicates whether JIDs from
* the new list which are also in the old list
* (regardless of affiliation) should be excluded
* from the delta. One reason to do this
* would be when you want to add a JID only if it
* doesn't have *any* existing affiliation at all.
* @param { boolean } remove_absentees - Indicates whether JIDs
* from the old list which are not in the new list
* should be considered removed and therefore be
* included in the delta with affiliation set
* to 'none'.
* @param { array } new_list - Array containing the new affiliations
* @param { array } old_list - Array containing the old affiliations
* @returns { array }
* The MUC utils object. Contains utility functions related to multi-user chat.
* @namespace stanza_utils
*/
u.computeAffiliationsDelta = function computeAffiliationsDelta (exclude_existing, remove_absentees, new_list, old_list) {
const new_jids = new_list.map(o => o.jid);
const old_jids = old_list.map(o => o.jid);
// Get the new affiliations
let delta = _.map(
_.difference(new_jids, old_jids),
(jid) => new_list[_.indexOf(new_jids, jid)]
);
if (!exclude_existing) {
// Get the changed affiliations
delta = delta.concat(_.filter(new_list, function (item) {
const idx = _.indexOf(old_jids, item.jid);
if (idx >= 0) {
return item.affiliation !== old_list[idx].affiliation;
}
return false;
}));
}
if (remove_absentees) {
// Get the removed affiliations
delta = delta.concat(
_.map(
_.difference(old_jids, new_jids),
(jid) => ({'jid': jid, 'affiliation': 'none'})
)
);
}
return delta;
};
/**
* Given an IQ stanza with a member list, create an array of objects containing
* known member data (e.g. jid, nick, role, affiliation).
* @private
* @method u#parseMemberListIQ
* @returns { MemberListItem[] }
*/
u.parseMemberListIQ = function parseMemberListIQ (iq) {
return sizzle(`query[xmlns="${Strophe.NS.MUC_ADMIN}"] item`, iq).map(
(item) => {
/**
* @typedef {Object} MemberListItem
* Either the JID or the nickname (or both) will be available.
* @property {string} affiliation
* @property {string} [role]
* @property {string} [jid]
* @property {string} [nick]
*/
const data = {
'affiliation': item.getAttribute('affiliation'),
}
const jid = item.getAttribute('jid');
if (u.isValidJID(jid)) {
data['jid'] = jid;
} else {
// XXX: Prosody sends nick for the jid attribute value
// Perhaps for anonymous room?
data['nick'] = jid;
}
const nick = item.getAttribute('nick');
if (nick) {
data['nick'] = nick;
}
const role = item.getAttribute('role');
if (role) {
data['role'] = nick;
}
return data;
const muc_utils = {
/**
* Given two lists of objects with 'jid', 'affiliation' and
* 'reason' properties, return a new list containing
* those objects that are new, changed or removed
* (depending on the 'remove_absentees' boolean).
*
* The affiliations for new and changed members stay the
* same, for removed members, the affiliation is set to 'none'.
*
* The 'reason' property is not taken into account when
* comparing whether affiliations have been changed.
* @private
* @method muc_utils#computeAffiliationsDelta
* @param { boolean } exclude_existing - Indicates whether JIDs from
* the new list which are also in the old list
* (regardless of affiliation) should be excluded
* from the delta. One reason to do this
* would be when you want to add a JID only if it
* doesn't have *any* existing affiliation at all.
* @param { boolean } remove_absentees - Indicates whether JIDs
* from the old list which are not in the new list
* should be considered removed and therefore be
* included in the delta with affiliation set
* to 'none'.
* @param { array } new_list - Array containing the new affiliations
* @param { array } old_list - Array containing the old affiliations
* @returns { array }
*/
computeAffiliationsDelta (exclude_existing, remove_absentees, new_list, old_list) {
const new_jids = new_list.map(o => o.jid);
const old_jids = old_list.map(o => o.jid);
// Get the new affiliations
let delta = difference(new_jids, old_jids).map(jid => new_list[indexOf(new_jids, jid)]);
if (!exclude_existing) {
// Get the changed affiliations
delta = delta.concat(new_list.filter(item => {
const idx = indexOf(old_jids, item.jid);
return idx >= 0 ? (item.affiliation !== old_list[idx].affiliation) : false;
}));
}
);
};
if (remove_absentees) { // Get the removed affiliations
delta = delta.concat(difference(old_jids, new_jids).map(jid => ({'jid': jid, 'affiliation': 'none'})));
}
return delta;
},
/**
* Given an IQ stanza with a member list, create an array of objects containing
* known member data (e.g. jid, nick, role, affiliation).
* @private
* @method muc_utils#parseMemberListIQ
* @returns { MemberListItem[] }
*/
parseMemberListIQ (iq) {
return sizzle(`query[xmlns="${Strophe.NS.MUC_ADMIN}"] item`, iq).map(
(item) => {
/**
* @typedef {Object} MemberListItem
* Either the JID or the nickname (or both) will be available.
* @property {string} affiliation
* @property {string} [role]
* @property {string} [jid]
* @property {string} [nick]
*/
const data = {
'affiliation': item.getAttribute('affiliation'),
}
const jid = item.getAttribute('jid');
if (u.isValidJID(jid)) {
data['jid'] = jid;
} else {
// XXX: Prosody sends nick for the jid attribute value
// Perhaps for anonymous room?
data['nick'] = jid;
}
const nick = item.getAttribute('nick');
if (nick) {
data['nick'] = nick;
}
const role = item.getAttribute('role');
if (role) {
data['role'] = nick;
}
return data;
}
);
},
}
export default muc_utils;