Extract affiliation-related methods out of the ChatRoom model
and put them together in a utils file
This commit is contained in:
parent
13e19eb7f8
commit
383f5c1d60
@ -323,13 +323,13 @@ window.addEventListener('converse-loaded', () => {
|
||||
await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
|
||||
|
||||
await room_creation_promise;
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
||||
const model = _converse.chatboxes.get(muc_jid);
|
||||
await u.waitUntil(() => (model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
|
||||
|
||||
const affs = _converse.muc_fetch_members;
|
||||
const all_affiliations = Array.isArray(affs) ? affs : (affs ? ['member', 'admin', 'owner'] : []);
|
||||
await mock.returnMemberLists(_converse, muc_jid, members, all_affiliations);
|
||||
return view.model.messages.fetched;
|
||||
return model.messages.fetched;
|
||||
};
|
||||
|
||||
mock.createContact = async function (_converse, name, ask, requesting, subscription) {
|
||||
|
153
src/headless/plugins/muc/affiliations/utils.js
Normal file
153
src/headless/plugins/muc/affiliations/utils.js
Normal file
@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @copyright The Converse.js contributors
|
||||
* @license Mozilla Public License (MPLv2)
|
||||
*/
|
||||
import log from "@converse/headless/log";
|
||||
import { api, converse } from '@converse/headless/core.js';
|
||||
import { difference, indexOf } from 'lodash-es';
|
||||
import { parseMemberListIQ } from '../parsers.js';
|
||||
|
||||
const { Strophe, $iq, u } = converse.env;
|
||||
|
||||
/**
|
||||
* Sends an IQ stanza to the server, asking it for the relevant affiliation list .
|
||||
* Returns an array of {@link MemberListItem} objects, representing occupants
|
||||
* that have the given affiliation.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @param { ("admin"|"owner"|"member") } affiliation
|
||||
* @param { String } muc_jid - The JID of the MUC for which the affiliation list should be fetched
|
||||
* @returns { Promise<MemberListItem[]> }
|
||||
*/
|
||||
export async function getAffiliationList (affiliation, muc_jid) {
|
||||
const iq = $iq({ 'to': muc_jid, 'type': 'get' })
|
||||
.c('query', { xmlns: Strophe.NS.MUC_ADMIN })
|
||||
.c('item', { 'affiliation': affiliation });
|
||||
const result = await api.sendIQ(iq, null, false);
|
||||
if (result === null) {
|
||||
const err_msg = `Error: timeout while fetching ${affiliation} list for MUC ${muc_jid}`;
|
||||
const err = new Error(err_msg);
|
||||
log.warn(err_msg);
|
||||
log.warn(result);
|
||||
return err;
|
||||
}
|
||||
if (u.isErrorStanza(result)) {
|
||||
const err_msg = `Error: not allowed to fetch ${affiliation} list for MUC ${muc_jid}`;
|
||||
const err = new Error(err_msg);
|
||||
log.warn(err_msg);
|
||||
log.warn(result);
|
||||
return err;
|
||||
}
|
||||
return parseMemberListIQ(result)
|
||||
.filter(p => p)
|
||||
.sort((a, b) => (a.nick < b.nick ? -1 : a.nick > b.nick ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to modify affiliations for users in this groupchat.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @param { Object[] } users
|
||||
* @param { string } users[].jid - The JID of the user whose affiliation will change
|
||||
* @param { Array } users[].affiliation - The new affiliation for this user
|
||||
* @param { string } [users[].reason] - An optional reason for the affiliation change
|
||||
* @returns { Promise }
|
||||
*/
|
||||
export function setAffiliations (muc_jid, users) {
|
||||
const affiliations = [...new Set(users.map(u => u.affiliation))];
|
||||
return Promise.all(affiliations.map(a => setAffiliation(a, muc_jid, users)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to set an affiliation for
|
||||
* the provided JIDs.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* Prosody doesn't accept multiple JIDs' affiliations
|
||||
* being set in one IQ stanza, so as a workaround we send
|
||||
* a separate stanza for each JID.
|
||||
* Related ticket: https://issues.prosody.im/345
|
||||
*
|
||||
* @param { String } affiliation - The affiliation
|
||||
* @param { String|Array<String> } jids - The JID(s) of the MUCs in which the
|
||||
* affiliations need to be set.
|
||||
* @param { object } members - A map of jids, affiliations and
|
||||
* optionally reasons. Only those entries with the
|
||||
* same affiliation as being currently set will be considered.
|
||||
* @returns { Promise } A promise which resolves and fails depending on the XMPP server response.
|
||||
*/
|
||||
export function setAffiliation (affiliation, muc_jids, members) {
|
||||
if (!Array.isArray(muc_jids)) {
|
||||
muc_jids = [muc_jids];
|
||||
}
|
||||
members = members.filter(m => [undefined, affiliation].includes(m.affiliation));
|
||||
return Promise.all(
|
||||
muc_jids.reduce((acc, jid) => [...acc, ...members.map(m => sendAffiliationIQ(affiliation, jid, m))], [])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an IQ stanza specifying an affiliation change.
|
||||
* @private
|
||||
* @param { String } affiliation: affiliation (could also be stored on the member object).
|
||||
* @param { String } muc_jid: The JID of the MUC in which the affiliation should be set.
|
||||
* @param { Object } member: Map containing the member's jid and optionally a reason and affiliation.
|
||||
*/
|
||||
function sendAffiliationIQ (affiliation, muc_jid, member) {
|
||||
const iq = $iq({ to: muc_jid, type: 'set' })
|
||||
.c('query', { xmlns: Strophe.NS.MUC_ADMIN })
|
||||
.c('item', {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
if (member.reason !== undefined) {
|
||||
iq.c('reason', member.reason);
|
||||
}
|
||||
return api.sendIQ(iq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 }
|
||||
*/
|
||||
export 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 = 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;
|
||||
}
|
@ -13,7 +13,7 @@ import ChatRoomOccupant from './occupant.js';
|
||||
import ChatRoomOccupants from './occupants.js';
|
||||
import log from '../../log';
|
||||
import muc_api from './api.js';
|
||||
import muc_utils from './utils.js';
|
||||
import { computeAffiliationsDelta } from './affiliations/utils.js';
|
||||
import u from '../../utils/form';
|
||||
import { Collection } from '@converse/skeletor/src/collection';
|
||||
import { _converse, api, converse } from '../../core.js';
|
||||
@ -265,7 +265,8 @@ converse.plugins.add('converse-muc', {
|
||||
);
|
||||
}
|
||||
|
||||
converse.env.muc_utils = muc_utils;
|
||||
// This is for tests (at least until we can import modules inside tests)
|
||||
converse.env.muc_utils = { computeAffiliationsDelta };
|
||||
Object.assign(api, muc_api);
|
||||
|
||||
/* https://xmpp.org/extensions/xep-0045.html
|
||||
|
@ -1,14 +1,14 @@
|
||||
import log from '../../log';
|
||||
import muc_utils from './utils.js';
|
||||
import p from '../../utils/parse-helpers';
|
||||
import sizzle from 'sizzle';
|
||||
import u from '../../utils/form';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
||||
import { _converse, api, converse } from '../../core.js';
|
||||
import { computeAffiliationsDelta, setAffiliations, getAffiliationList } from './affiliations/utils.js';
|
||||
import { debounce, intersection, invoke, isElement, pick, zipObject } from 'lodash-es';
|
||||
import { isArchived } from '@converse/headless/shared/parsers';
|
||||
import { parseMemberListIQ, parseMUCMessage, parseMUCPresence } from './parsers.js';
|
||||
import { parseMUCMessage, parseMUCPresence } from './parsers.js';
|
||||
import { sendMarker } from '@converse/headless/shared/actions';
|
||||
|
||||
const OWNER_COMMANDS = ['owner'];
|
||||
@ -1136,29 +1136,6 @@ const ChatRoomMixin = {
|
||||
this.features.save(attrs);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to set an affiliation for
|
||||
* the provided JIDs.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* Prosody doesn't accept multiple JIDs' affiliations
|
||||
* being set in one IQ stanza, so as a workaround we send
|
||||
* a separate stanza for each JID.
|
||||
* Related ticket: https://issues.prosody.im/345
|
||||
*
|
||||
* @private
|
||||
* @method _converse.ChatRoom#setAffiliation
|
||||
* @param { string } affiliation - The affiliation
|
||||
* @param { object } members - A map of jids, affiliations and
|
||||
* optionally reasons. Only those entries with the
|
||||
* same affiliation as being currently set will be considered.
|
||||
* @returns { Promise } A promise which resolves and fails depending on the XMPP server response.
|
||||
*/
|
||||
setAffiliation (affiliation, members) {
|
||||
members = members.filter(m => m.affiliation === undefined || m.affiliation === affiliation);
|
||||
return Promise.all(members.map(m => this.sendAffiliationIQ(affiliation, m)));
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a <field> element, return a copy with a <value> child if
|
||||
* we can find a value for it in this rooms config.
|
||||
@ -1388,46 +1365,6 @@ const ChatRoomMixin = {
|
||||
return this.occupants.findWhere({ 'jid': _converse.bare_jid });
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza specifying an affiliation change.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#
|
||||
* @param { String } affiliation: affiliation
|
||||
* (could also be stored on the member object).
|
||||
* @param { Object } member: Map containing the member's jid and
|
||||
* optionally a reason and affiliation.
|
||||
*/
|
||||
sendAffiliationIQ (affiliation, member) {
|
||||
const iq = $iq({ to: this.get('jid'), type: 'set' })
|
||||
.c('query', { xmlns: Strophe.NS.MUC_ADMIN })
|
||||
.c('item', {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
if (member.reason !== undefined) {
|
||||
iq.c('reason', member.reason);
|
||||
}
|
||||
return api.sendIQ(iq);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to modify affiliations for users in this groupchat.
|
||||
*
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @private
|
||||
* @method _converse.ChatRoom#setAffiliations
|
||||
* @param { Object[] } members
|
||||
* @param { string } members[].jid - The JID of the user whose affiliation will change
|
||||
* @param { Array } members[].affiliation - The new affiliation for this user
|
||||
* @param { string } [members[].reason] - An optional reason for the affiliation change
|
||||
* @returns { Promise }
|
||||
*/
|
||||
setAffiliations (members) {
|
||||
const affiliations = [...new Set(members.map(m => m.affiliation))];
|
||||
return Promise.all(affiliations.map(a => this.setAffiliation(a, members)));
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza to modify an occupant's role
|
||||
* @private
|
||||
@ -1521,40 +1458,6 @@ const ChatRoomMixin = {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends an IQ stanza to the server, asking it for the relevant affiliation list .
|
||||
* Returns an array of {@link MemberListItem} objects, representing occupants
|
||||
* that have the given affiliation.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @private
|
||||
* @method _converse.ChatRoom#getAffiliationList
|
||||
* @param { ("admin"|"owner"|"member") } affiliation
|
||||
* @returns { Promise<MemberListItem[]> }
|
||||
*/
|
||||
async getAffiliationList (affiliation) {
|
||||
const iq = $iq({ to: this.get('jid'), type: 'get' })
|
||||
.c('query', { xmlns: Strophe.NS.MUC_ADMIN })
|
||||
.c('item', { 'affiliation': affiliation });
|
||||
const result = await api.sendIQ(iq, null, false);
|
||||
if (result === null) {
|
||||
const err_msg = `Error: timeout while fetching ${affiliation} list for MUC ${this.get('jid')}`;
|
||||
const err = new Error(err_msg);
|
||||
log.warn(err_msg);
|
||||
log.warn(result);
|
||||
return err;
|
||||
}
|
||||
if (u.isErrorStanza(result)) {
|
||||
const err_msg = `Error: not allowed to fetch ${affiliation} list for MUC ${this.get('jid')}`;
|
||||
const err = new Error(err_msg);
|
||||
log.warn(err_msg);
|
||||
log.warn(result);
|
||||
return err;
|
||||
}
|
||||
return parseMemberListIQ(result)
|
||||
.filter(p => p)
|
||||
.sort((a, b) => (a.nick < b.nick ? -1 : a.nick > b.nick ? 1 : 0));
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the lists of users with the given affiliations.
|
||||
* Then compute the delta between those users and
|
||||
@ -1569,10 +1472,11 @@ const ChatRoomMixin = {
|
||||
* to update the list.
|
||||
*/
|
||||
async updateMemberLists (members) {
|
||||
const muc_jid = this.get('jid');
|
||||
const all_affiliations = ['member', 'admin', 'owner'];
|
||||
const aff_lists = await Promise.all(all_affiliations.map(a => this.getAffiliationList(a)));
|
||||
const aff_lists = await Promise.all(all_affiliations.map(a => getAffiliationList(a, muc_jid)));
|
||||
const old_members = aff_lists.reduce((acc, val) => (u.isErrorObject(val) ? acc : [...val, ...acc]), []);
|
||||
await this.setAffiliations(muc_utils.computeAffiliationsDelta(true, false, members, old_members));
|
||||
await setAffiliations(muc_jid, computeAffiliationsDelta(true, false, members, old_members));
|
||||
await this.occupants.fetchMembers();
|
||||
},
|
||||
|
||||
|
@ -3,6 +3,7 @@ import u from '../../utils/form';
|
||||
import { Collection } from '@converse/skeletor/src/collection';
|
||||
import { Strophe } from 'strophe.js/src/strophe';
|
||||
import { _converse, api } from '../../core.js';
|
||||
import { getAffiliationList } from './affiliations/utils.js';
|
||||
|
||||
const MUC_ROLE_WEIGHTS = {
|
||||
'moderator': 1,
|
||||
@ -43,7 +44,8 @@ const ChatRoomOccupants = Collection.extend({
|
||||
if (affiliations.length === 0) {
|
||||
return;
|
||||
}
|
||||
const aff_lists = await Promise.all(affiliations.map(a => this.chatroom.getAffiliationList(a)));
|
||||
const muc_jid = this.chatroom.get('jid');
|
||||
const aff_lists = await Promise.all(affiliations.map(a => getAffiliationList(a, muc_jid)));
|
||||
const new_members = aff_lists.reduce((acc, val) => (u.isErrorObject(val) ? acc : [...val, ...acc]), []);
|
||||
const known_affiliations = affiliations.filter(
|
||||
a => !u.isErrorObject(aff_lists[affiliations.indexOf(a)])
|
||||
|
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* @copyright The Converse.js contributors
|
||||
* @license Mozilla Public License (MPLv2)
|
||||
* @description This is the MUC utilities module.
|
||||
*/
|
||||
import { difference, indexOf } from "lodash-es";
|
||||
|
||||
/**
|
||||
* The MUC utils object. Contains utility functions related to multi-user chat.
|
||||
* @namespace muc_utils
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export default muc_utils;
|
@ -1,9 +1,10 @@
|
||||
import BootstrapModal from "./base.js";
|
||||
import BootstrapModal from "modals/base.js";
|
||||
import log from "@converse/headless/log";
|
||||
import tpl_moderator_tools_modal from "./templates/moderator-tools.js";
|
||||
import tpl_moderator_tools_modal from "../templates/moderator-tools.js";
|
||||
import { AFFILIATIONS, ROLES } from "@converse/headless/plugins/muc/index.js";
|
||||
import { __ } from '../i18n';
|
||||
import { __ } from 'i18n';
|
||||
import { api, converse } from "@converse/headless/core";
|
||||
import { getAffiliationList, setAffiliation } from '@converse/headless/plugins/muc/affiliations/utils.js'
|
||||
|
||||
const { Strophe, sizzle } = converse.env;
|
||||
const u = converse.env.utils;
|
||||
@ -33,7 +34,8 @@ export default BootstrapModal.extend({
|
||||
const chatroom = this.chatroomview.model;
|
||||
const affiliation = this.model.get('affiliation');
|
||||
if (this.shouldFetchAffiliationsList()) {
|
||||
this.users_with_affiliation = await chatroom.getAffiliationList(affiliation);
|
||||
const muc_jid = chatroom.get('jid');
|
||||
this.users_with_affiliation = await getAffiliationList(affiliation, muc_jid);
|
||||
} else {
|
||||
this.users_with_affiliation = chatroom.getOccupantsWithAffiliation(affiliation);
|
||||
}
|
||||
@ -157,8 +159,9 @@ export default BootstrapModal.extend({
|
||||
'reason': data.get('reason')
|
||||
}
|
||||
const current_affiliation = this.model.get('affiliation');
|
||||
const muc_jid = this.chatroomview.model.get('jid');
|
||||
try {
|
||||
await this.chatroomview.model.setAffiliation(affiliation, [attrs]);
|
||||
await setAffiliation(affiliation, muc_jid, [attrs]);
|
||||
} catch (e) {
|
||||
if (e === null) {
|
||||
this.alert(__('Timeout error while trying to set the affiliation'), 'danger');
|
@ -1,5 +1,5 @@
|
||||
import BaseChatView from 'shared/chat/baseview.js';
|
||||
import ModeratorToolsModal from 'modals/moderator-tools.js';
|
||||
import ModeratorToolsModal from './modals/moderator-tools.js';
|
||||
import log from '@converse/headless/log';
|
||||
import tpl_muc from './templates/muc.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import spinner from "templates/spinner.js";
|
||||
import { __ } from 'i18n';
|
||||
import { html } from "lit-html";
|
||||
import { __ } from '../../i18n';
|
||||
import spinner from "../../templates/spinner.js";
|
||||
import { modal_header_close_button } from "./buttons.js"
|
||||
import { modal_header_close_button } from "modals/templates/buttons.js"
|
||||
|
||||
|
||||
function getRoleHelpText (role) {
|
@ -3107,7 +3107,6 @@ describe("Groupchats", function () {
|
||||
|
||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
spyOn(view.model, 'setAffiliation').and.callThrough();
|
||||
spyOn(view.model, 'validateRoleOrAffiliationChangeArgs').and.callThrough();
|
||||
|
||||
let presence = $pres({
|
||||
@ -3136,7 +3135,10 @@ describe("Groupchats", function () {
|
||||
expect(err_msg.textContent.trim()).toBe(
|
||||
"Error: the \"owner\" command takes two arguments, the user's nickname and optionally a reason.");
|
||||
|
||||
expect(view.model.setAffiliation).not.toHaveBeenCalled();
|
||||
const sel = 'iq[type="set"] query[xmlns="http://jabber.org/protocol/muc#admin"]';
|
||||
const stanzas = _converse.connection.IQ_stanzas.filter(s => sizzle(sel, s).length);
|
||||
expect(stanzas.length).toBe(0);
|
||||
|
||||
// XXX: Calling onFormSubmitted directly, trying
|
||||
// again via triggering Event doesn't work for some weird
|
||||
// reason.
|
||||
@ -3146,7 +3148,7 @@ describe("Groupchats", function () {
|
||||
expect(Array.from(view.querySelectorAll('.chat-error')).pop().textContent.trim()).toBe(
|
||||
"Error: couldn't find a groupchat participant based on your arguments");
|
||||
|
||||
expect(view.model.setAffiliation).not.toHaveBeenCalled();
|
||||
expect(_converse.connection.IQ_stanzas.filter(s => sizzle(sel, s).length).length).toBe(0);
|
||||
|
||||
// Call now with the correct of arguments.
|
||||
// XXX: Calling onFormSubmitted directly, trying
|
||||
@ -3156,7 +3158,6 @@ describe("Groupchats", function () {
|
||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
||||
|
||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
|
||||
expect(view.model.setAffiliation).toHaveBeenCalled();
|
||||
// Check that the member list now gets updated
|
||||
expect(Strophe.serialize(sent_IQ)).toBe(
|
||||
`<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
|
||||
@ -3196,7 +3197,6 @@ describe("Groupchats", function () {
|
||||
|
||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
spyOn(view.model, 'setAffiliation').and.callThrough();
|
||||
spyOn(view.model, 'validateRoleOrAffiliationChangeArgs').and.callThrough();
|
||||
|
||||
let presence = $pres({
|
||||
@ -3224,7 +3224,10 @@ describe("Groupchats", function () {
|
||||
await u.waitUntil(() => view.querySelector('.message:last-child')?.textContent?.trim() ===
|
||||
"Error: the \"ban\" command takes two arguments, the user's nickname and optionally a reason.");
|
||||
|
||||
expect(view.model.setAffiliation).not.toHaveBeenCalled();
|
||||
const sel = 'iq[type="set"] query[xmlns="http://jabber.org/protocol/muc#admin"]';
|
||||
const stanzas = _converse.connection.IQ_stanzas.filter(s => sizzle(sel, s).length);
|
||||
expect(stanzas.length).toBe(0);
|
||||
|
||||
// Call now with the correct amount of arguments.
|
||||
// XXX: Calling onFormSubmitted directly, trying
|
||||
// again via triggering Event doesn't work for some weird
|
||||
@ -3233,7 +3236,6 @@ describe("Groupchats", function () {
|
||||
bottom_panel.onFormSubmitted(new Event('submit'));
|
||||
|
||||
expect(view.model.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(2);
|
||||
expect(view.model.setAffiliation).toHaveBeenCalled();
|
||||
// Check that the member list now gets updated
|
||||
expect(Strophe.serialize(sent_IQ)).toBe(
|
||||
`<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
|
||||
|
@ -4,6 +4,7 @@ import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
import { html } from "lit-html";
|
||||
import { parseMessageForCommands } from 'plugins/chatview/utils.js';
|
||||
import { setAffiliation } from '@converse/headless/plugins/muc/affiliations/utils.js';
|
||||
|
||||
const { Strophe, $pres, $iq, sizzle, u } = converse.env;
|
||||
|
||||
@ -187,10 +188,10 @@ function setRole (muc, command, args, required_affiliations = [], required_roles
|
||||
}
|
||||
|
||||
|
||||
function setAffiliation (muc, command, args, required_affiliations) {
|
||||
function verifyAndSetAffiliation (muc, command, args, required_affiliations) {
|
||||
const affiliation = COMMAND_TO_AFFILIATION[command];
|
||||
if (!affiliation) {
|
||||
throw Error(`ChatRoomView#setAffiliation called with invalid command: ${command}`);
|
||||
throw Error(`verifyAffiliations called with invalid command: ${command}`);
|
||||
}
|
||||
if (!muc.verifyAffiliations(required_affiliations)) {
|
||||
return false;
|
||||
@ -223,8 +224,8 @@ function setAffiliation (muc, command, args, required_affiliations) {
|
||||
if (occupant && api.settings.get('auto_register_muc_nickname')) {
|
||||
attrs['nick'] = occupant.get('nick');
|
||||
}
|
||||
muc
|
||||
.setAffiliation(affiliation, [attrs])
|
||||
|
||||
setAffiliation(affiliation, muc.get('jid'), [attrs])
|
||||
.then(() => muc.occupants.fetchMembers())
|
||||
.catch(err => muc.onCommandError(err));
|
||||
}
|
||||
@ -249,11 +250,11 @@ export function parseMessageForMUCCommands (muc, text) {
|
||||
|
||||
switch (command) {
|
||||
case 'admin': {
|
||||
setAffiliation(muc, command, args, ['owner']);
|
||||
verifyAndSetAffiliation(muc, command, args, ['owner']);
|
||||
break;
|
||||
}
|
||||
case 'ban': {
|
||||
setAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
verifyAndSetAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
break;
|
||||
}
|
||||
case 'modtools': {
|
||||
@ -293,7 +294,7 @@ export function parseMessageForMUCCommands (muc, text) {
|
||||
break;
|
||||
}
|
||||
case 'member': {
|
||||
setAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
verifyAndSetAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
break;
|
||||
}
|
||||
case 'nick': {
|
||||
@ -316,7 +317,7 @@ export function parseMessageForMUCCommands (muc, text) {
|
||||
break;
|
||||
}
|
||||
case 'owner':
|
||||
setAffiliation(muc, command, args, ['owner']);
|
||||
verifyAndSetAffiliation(muc, command, args, ['owner']);
|
||||
break;
|
||||
case 'op': {
|
||||
setRole(muc, command, args, ['admin', 'owner']);
|
||||
@ -336,7 +337,7 @@ export function parseMessageForMUCCommands (muc, text) {
|
||||
break;
|
||||
}
|
||||
case 'revoke': {
|
||||
setAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
verifyAndSetAffiliation(muc, command, args, ['admin', 'owner']);
|
||||
break;
|
||||
}
|
||||
case 'topic':
|
||||
|
Loading…
Reference in New Issue
Block a user