parent
07b2425ff9
commit
fa562cabae
|
@ -10,6 +10,7 @@
|
||||||
- If `auto_register_muc_nickname` is set, make sure to register when the user changes current nick.
|
- If `auto_register_muc_nickname` is set, make sure to register when the user changes current nick.
|
||||||
- #1322: Display occupants’ avatars in the occupants list
|
- #1322: Display occupants’ avatars in the occupants list
|
||||||
- #1419: Clicking on avatar should show bigger version
|
- #1419: Clicking on avatar should show bigger version
|
||||||
|
- #1426: Don't fetch member list if not affiliated
|
||||||
- #2647: Singleton mode doesn't work
|
- #2647: Singleton mode doesn't work
|
||||||
- #2704: Send button doesn't work in a multi-user chat
|
- #2704: Send button doesn't work in a multi-user chat
|
||||||
- #2725: Send new presence status to all connected MUCs
|
- #2725: Send new presence status to all connected MUCs
|
||||||
|
|
|
@ -79,6 +79,7 @@ module.exports = function(config) {
|
||||||
{ pattern: "src/plugins/muc-views/tests/mentions.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/mentions.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/mep.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/mep.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/modtools.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/modtools.js", type: 'module' },
|
||||||
|
{ pattern: "src/plugins/muc-views/tests/member-lists.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/muc-api.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/muc-api.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/muc-mentions.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/muc-mentions.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/muc-views/tests/muc-messages.js", type: 'module' },
|
{ pattern: "src/plugins/muc-views/tests/muc-messages.js", type: 'module' },
|
||||||
|
|
6
src/headless/plugins/muc/constants.js
Normal file
6
src/headless/plugins/muc/constants.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export const MUC_ROLE_WEIGHTS = {
|
||||||
|
'moderator': 1,
|
||||||
|
'participant': 2,
|
||||||
|
'visitor': 3,
|
||||||
|
'none': 2
|
||||||
|
};
|
|
@ -1396,12 +1396,11 @@ const ChatRoomMixin = {
|
||||||
/**
|
/**
|
||||||
* Get the {@link _converse.ChatRoomOccupant} instance which
|
* Get the {@link _converse.ChatRoomOccupant} instance which
|
||||||
* represents the current user.
|
* represents the current user.
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoom#getOwnOccupant
|
* @method _converse.ChatRoom#getOwnOccupant
|
||||||
* @returns { _converse.ChatRoomOccupant }
|
* @returns { _converse.ChatRoomOccupant }
|
||||||
*/
|
*/
|
||||||
getOwnOccupant () {
|
getOwnOccupant () {
|
||||||
return this.occupants.findWhere({ 'jid': _converse.bare_jid });
|
return this.occupants.getOwnOccupant();
|
||||||
},
|
},
|
||||||
|
|
||||||
async setNickname (nick) {
|
async setNickname (nick) {
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
import ChatRoomOccupant from './occupant.js';
|
import ChatRoomOccupant from './occupant.js';
|
||||||
import u from '../../utils/form';
|
import u from '../../utils/form';
|
||||||
import { Collection } from '@converse/skeletor/src/collection';
|
import { Collection } from '@converse/skeletor/src/collection';
|
||||||
|
import { MUC_ROLE_WEIGHTS } from './constants.js';
|
||||||
import { Strophe } from 'strophe.js/src/strophe';
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
import { _converse, api } from '../../core.js';
|
import { _converse, api } from '../../core.js';
|
||||||
import { getAffiliationList } from './affiliations/utils.js';
|
import { getAffiliationList } from './affiliations/utils.js';
|
||||||
|
|
||||||
const MUC_ROLE_WEIGHTS = {
|
|
||||||
'moderator': 1,
|
|
||||||
'participant': 2,
|
|
||||||
'visitor': 3,
|
|
||||||
'none': 2
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of {@link _converse.ChatRoomOccupant} instances, representing participants in a MUC.
|
* A list of {@link _converse.ChatRoomOccupant} instances, representing participants in a MUC.
|
||||||
|
@ -34,12 +28,26 @@ const ChatRoomOccupants = Collection.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link _converse.ChatRoomOccupant} instance which
|
||||||
|
* represents the current user.
|
||||||
|
* @method _converse.ChatRoomOccupants#getOwnOccupant
|
||||||
|
* @returns { _converse.ChatRoomOccupant }
|
||||||
|
*/
|
||||||
|
getOwnOccupant () {
|
||||||
|
return this.findWhere({ 'jid': _converse.bare_jid });
|
||||||
|
},
|
||||||
|
|
||||||
getAutoFetchedAffiliationLists () {
|
getAutoFetchedAffiliationLists () {
|
||||||
const affs = api.settings.get('muc_fetch_members');
|
const affs = api.settings.get('muc_fetch_members');
|
||||||
return Array.isArray(affs) ? affs : affs ? ['member', 'admin', 'owner'] : [];
|
return Array.isArray(affs) ? affs : affs ? ['member', 'admin', 'owner'] : [];
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchMembers () {
|
async fetchMembers () {
|
||||||
|
if (!['member', 'admin', 'owner'].includes(this.getOwnOccupant()?.get('affiliation'))) {
|
||||||
|
// https://xmpp.org/extensions/xep-0045.html#affil-priv
|
||||||
|
return;
|
||||||
|
}
|
||||||
const affiliations = this.getAutoFetchedAffiliationLists();
|
const affiliations = this.getAutoFetchedAffiliationLists();
|
||||||
if (affiliations.length === 0) {
|
if (affiliations.length === 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -59,26 +67,18 @@ const ChatRoomOccupants = Collection.extend({
|
||||||
!new_jids.includes(m.get('jid'))
|
!new_jids.includes(m.get('jid'))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
removed_members.forEach(occupant => {
|
removed_members.forEach(occupant => {
|
||||||
if (occupant.get('jid') === _converse.bare_jid) {
|
if (occupant.get('jid') === _converse.bare_jid) {
|
||||||
return;
|
return;
|
||||||
}
|
} else if (occupant.get('show') === 'offline') {
|
||||||
if (occupant.get('show') === 'offline') {
|
|
||||||
occupant.destroy();
|
occupant.destroy();
|
||||||
} else {
|
} else {
|
||||||
occupant.save('affiliation', null);
|
occupant.save('affiliation', null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
new_members.forEach(attrs => {
|
new_members.forEach(attrs => {
|
||||||
const occupant = attrs.jid
|
const occupant = this.findOccupant(attrs);
|
||||||
? this.findOccupant({ 'jid': attrs.jid })
|
occupant ? occupant.save(attrs) : this.create(attrs);
|
||||||
: this.findOccupant({ 'nick': attrs.nick });
|
|
||||||
if (occupant) {
|
|
||||||
occupant.save(attrs);
|
|
||||||
} else {
|
|
||||||
this.create(attrs);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
/**
|
/**
|
||||||
* Triggered once the member lists for this MUC have been fetched and processed.
|
* Triggered once the member lists for this MUC have been fetched and processed.
|
||||||
|
@ -101,7 +101,6 @@ const ChatRoomOccupants = Collection.extend({
|
||||||
* If we have a JID, we use that as lookup variable,
|
* If we have a JID, we use that as lookup variable,
|
||||||
* otherwise we use the nick. We don't always have both,
|
* otherwise we use the nick. We don't always have both,
|
||||||
* but should have at least one or the other.
|
* but should have at least one or the other.
|
||||||
* @private
|
|
||||||
* @method _converse.ChatRoomOccupants#findOccupant
|
* @method _converse.ChatRoomOccupants#findOccupant
|
||||||
* @param { OccupantData } data
|
* @param { OccupantData } data
|
||||||
*/
|
*/
|
||||||
|
|
301
src/plugins/muc-views/tests/member-lists.js
Normal file
301
src/plugins/muc-views/tests/member-lists.js
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
/*global mock, converse */
|
||||||
|
const { $iq, Strophe, u } = converse.env;
|
||||||
|
|
||||||
|
describe("A Groupchat", function () {
|
||||||
|
|
||||||
|
describe("upon being entered", function () {
|
||||||
|
|
||||||
|
it("will fetch the member list if muc_fetch_members is true",
|
||||||
|
mock.initConverse([], {'muc_fetch_members': true}, async function (_converse) {
|
||||||
|
|
||||||
|
const { api } = _converse;
|
||||||
|
let sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||||
|
let view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(3);
|
||||||
|
|
||||||
|
// Check in reverse order that we requested all three lists
|
||||||
|
const owner_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(owner_iq)).toBe(
|
||||||
|
`<iq id="${owner_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
const admin_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(admin_iq)).toBe(
|
||||||
|
`<iq id="${admin_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
const member_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(member_iq)).toBe(
|
||||||
|
`<iq id="${member_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
view.close();
|
||||||
|
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
api.settings.set('muc_fetch_members', false);
|
||||||
|
await mock.openAndEnterChatRoom(_converse, 'orchard@montague.lit', 'romeo');
|
||||||
|
view = _converse.chatboxviews.get('orchard@montague.lit');
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(0);
|
||||||
|
await view.close();
|
||||||
|
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
api.settings.set('muc_fetch_members', ['admin']);
|
||||||
|
await mock.openAndEnterChatRoom(_converse, 'courtyard@montague.lit', 'romeo');
|
||||||
|
view = _converse.chatboxviews.get('courtyard@montague.lit');
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(1);
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation="admin"]')).length).toBe(1);
|
||||||
|
view.close();
|
||||||
|
|
||||||
|
_converse.connection.IQ_stanzas = [];
|
||||||
|
sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
api.settings.set('muc_fetch_members', ['owner']);
|
||||||
|
await mock.openAndEnterChatRoom(_converse, 'garden@montague.lit', 'romeo');
|
||||||
|
view = _converse.chatboxviews.get('garden@montague.lit');
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(1);
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation="owner"]')).length).toBe(1);
|
||||||
|
view.close();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("will not fetch the member list if the user is not affiliated",
|
||||||
|
mock.initConverse([], {'muc_fetch_members': true}, async function (_converse) {
|
||||||
|
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
|
||||||
|
// Join MUC without an affiliation
|
||||||
|
const model = await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], [], true, {}, 'none', 'participant');
|
||||||
|
await u.waitUntil(() => model.occupants.fetchMembers.calls.count());
|
||||||
|
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("when fetching the member lists", function () {
|
||||||
|
|
||||||
|
it("gracefully handles being forbidden from fetching the lists for certain affiliations",
|
||||||
|
mock.initConverse([], {'muc_fetch_members': true}, async function (_converse) {
|
||||||
|
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
const features = [
|
||||||
|
'http://jabber.org/protocol/muc',
|
||||||
|
'jabber:iq:register',
|
||||||
|
'muc_hidden',
|
||||||
|
'muc_membersonly',
|
||||||
|
'muc_passwordprotected',
|
||||||
|
Strophe.NS.MAM,
|
||||||
|
Strophe.NS.SID
|
||||||
|
];
|
||||||
|
const nick = 'romeo';
|
||||||
|
await _converse.api.rooms.open(muc_jid);
|
||||||
|
await mock.getRoomFeatures(_converse, muc_jid, features);
|
||||||
|
await mock.waitForReservedNick(_converse, muc_jid, nick);
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Check in reverse order that we requested all three lists
|
||||||
|
const owner_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(owner_iq)).toBe(
|
||||||
|
`<iq id="${owner_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
const admin_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(admin_iq)).toBe(
|
||||||
|
`<iq id="${admin_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
const member_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(member_iq)).toBe(
|
||||||
|
`<iq id="${member_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
// It might be that the user is not allowed to fetch certain lists.
|
||||||
|
let err_stanza = u.toStanza(
|
||||||
|
`<iq xmlns="jabber:client" type="error" to="${_converse.jid}" from="${muc_jid}" id="${admin_iq.getAttribute('id')}">
|
||||||
|
<error type="auth"><forbidden xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
|
||||||
|
</iq>`);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(err_stanza));
|
||||||
|
|
||||||
|
err_stanza = u.toStanza(
|
||||||
|
`<iq xmlns="jabber:client" type="error" to="${_converse.jid}" from="${muc_jid}" id="${owner_iq.getAttribute('id')}">
|
||||||
|
<error type="auth"><forbidden xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
|
||||||
|
</iq>`);
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(err_stanza));
|
||||||
|
|
||||||
|
// Now the service sends the member lists to the user
|
||||||
|
const member_list_stanza = $iq({
|
||||||
|
'from': muc_jid,
|
||||||
|
'id': member_iq.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'type': 'result'
|
||||||
|
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'member',
|
||||||
|
'jid': 'hag66@shakespeare.lit',
|
||||||
|
'nick': 'thirdwitch',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(member_list_stanza));
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.model.occupants.length > 1);
|
||||||
|
expect(view.model.occupants.length).toBe(2);
|
||||||
|
// The existing owner occupant should not have their
|
||||||
|
// affiliation removed due to the owner list
|
||||||
|
// not being returned (forbidden err).
|
||||||
|
expect(view.model.occupants.findWhere({'jid': _converse.bare_jid}).get('affiliation')).toBe('owner');
|
||||||
|
expect(view.model.occupants.findWhere({'jid': 'hag66@shakespeare.lit'}).get('affiliation')).toBe('member');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Someone being invited to a groupchat", function () {
|
||||||
|
|
||||||
|
it("will first be added to the member list if the groupchat is members only",
|
||||||
|
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
||||||
|
|
||||||
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
|
spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
|
||||||
|
const sent_IQs = _converse.connection.IQ_stanzas;
|
||||||
|
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||||
|
const nick = 'romeo';
|
||||||
|
const room_creation_promise = _converse.api.rooms.open(muc_jid, {nick});
|
||||||
|
|
||||||
|
// Check that the groupchat queried for the features.
|
||||||
|
let stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`)).pop());
|
||||||
|
expect(Strophe.serialize(stanza)).toBe(
|
||||||
|
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute("id")}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/disco#info"/>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
// State that the chat is members-only via the features IQ
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
const features_stanza = $iq({
|
||||||
|
from: 'coven@chat.shakespeare.lit',
|
||||||
|
'id': stanza.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/desktop',
|
||||||
|
'type': 'result'
|
||||||
|
})
|
||||||
|
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'conference',
|
||||||
|
'name': 'A Dark Cave',
|
||||||
|
'type': 'text'
|
||||||
|
}).up()
|
||||||
|
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
||||||
|
.c('feature', {'var': 'muc_hidden'}).up()
|
||||||
|
.c('feature', {'var': 'muc_temporary'}).up()
|
||||||
|
.c('feature', {'var': 'muc_membersonly'}).up();
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
||||||
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
|
await u.waitUntil(() => sent_stanzas.filter(s => s.matches(`presence[to="${muc_jid}/${nick}"]`)).pop());
|
||||||
|
expect(view.model.features.get('membersonly')).toBeTruthy();
|
||||||
|
|
||||||
|
await room_creation_promise;
|
||||||
|
await mock.createContacts(_converse, 'current');
|
||||||
|
|
||||||
|
let sent_stanza, sent_id;
|
||||||
|
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||||
|
if (stanza.nodeName === 'message') {
|
||||||
|
sent_id = stanza.getAttribute('id');
|
||||||
|
sent_stanza = stanza;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const invitee_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||||
|
const reason = "Please join this groupchat";
|
||||||
|
view.model.directInvite(invitee_jid, reason);
|
||||||
|
|
||||||
|
// Check in reverse order that we requested all three lists
|
||||||
|
const owner_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(owner_iq)).toBe(
|
||||||
|
`<iq id="${owner_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
const admin_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(admin_iq)).toBe(
|
||||||
|
`<iq id="${admin_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
const member_iq = sent_IQs.pop();
|
||||||
|
expect(Strophe.serialize(member_iq)).toBe(
|
||||||
|
`<iq id="${member_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
// Now the service sends the member lists to the user
|
||||||
|
const member_list_stanza = $iq({
|
||||||
|
'from': 'coven@chat.shakespeare.lit',
|
||||||
|
'id': member_iq.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'type': 'result'
|
||||||
|
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'member',
|
||||||
|
'jid': 'hag66@shakespeare.lit',
|
||||||
|
'nick': 'thirdwitch',
|
||||||
|
'role': 'participant'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(member_list_stanza));
|
||||||
|
|
||||||
|
const admin_list_stanza = $iq({
|
||||||
|
'from': 'coven@chat.shakespeare.lit',
|
||||||
|
'id': admin_iq.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'type': 'result'
|
||||||
|
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'admin',
|
||||||
|
'jid': 'wiccarocks@shakespeare.lit',
|
||||||
|
'nick': 'secondwitch'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(admin_list_stanza));
|
||||||
|
|
||||||
|
const owner_list_stanza = $iq({
|
||||||
|
'from': 'coven@chat.shakespeare.lit',
|
||||||
|
'id': owner_iq.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'type': 'result'
|
||||||
|
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||||
|
.c('item', {
|
||||||
|
'affiliation': 'owner',
|
||||||
|
'jid': 'crone1@shakespeare.lit',
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(owner_list_stanza));
|
||||||
|
|
||||||
|
// Converse puts the user on the member list
|
||||||
|
stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/muc#admin"]`)).pop());
|
||||||
|
expect(stanza.outerHTML,
|
||||||
|
`<iq id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
||||||
|
`<query xmlns="http://jabber.org/protocol/muc#admin">`+
|
||||||
|
`<item affiliation="member" jid="${invitee_jid}">`+
|
||||||
|
`<reason>Please join this groupchat</reason>`+
|
||||||
|
`</item>`+
|
||||||
|
`</query>`+
|
||||||
|
`</iq>`);
|
||||||
|
|
||||||
|
const result = $iq({
|
||||||
|
'from': 'coven@chat.shakespeare.lit',
|
||||||
|
'id': stanza.getAttribute('id'),
|
||||||
|
'to': 'romeo@montague.lit/orchard',
|
||||||
|
'type': 'result'
|
||||||
|
});
|
||||||
|
_converse.connection._dataRecv(mock.createRequest(result));
|
||||||
|
|
||||||
|
await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
|
||||||
|
|
||||||
|
// Finally check that the user gets invited.
|
||||||
|
expect(Strophe.serialize(sent_stanza)).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||||
|
`<message from="romeo@montague.lit/orchard" id="${sent_id}" to="${invitee_jid}" xmlns="jabber:client">`+
|
||||||
|
`<x jid="coven@chat.shakespeare.lit" reason="Please join this groupchat" xmlns="jabber:x:conference"/>`+
|
||||||
|
`</message>`
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
});
|
|
@ -1,12 +1,6 @@
|
||||||
/*global mock, converse */
|
/*global mock, converse */
|
||||||
|
|
||||||
const $pres = converse.env.$pres;
|
const { $pres, $iq, $msg, Strophe, Promise, sizzle, u } = converse.env;
|
||||||
const $iq = converse.env.$iq;
|
|
||||||
const $msg = converse.env.$msg;
|
|
||||||
const Strophe = converse.env.Strophe;
|
|
||||||
const Promise = converse.env.Promise;
|
|
||||||
const sizzle = converse.env.sizzle;
|
|
||||||
const u = converse.env.utils;
|
|
||||||
|
|
||||||
describe("Groupchats", function () {
|
describe("Groupchats", function () {
|
||||||
|
|
||||||
|
@ -284,145 +278,6 @@ describe("Groupchats", function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
describe("upon being entered", function () {
|
|
||||||
|
|
||||||
it("will fetch the member list if muc_fetch_members is true",
|
|
||||||
mock.initConverse([], {'muc_fetch_members': true}, async function (_converse) {
|
|
||||||
|
|
||||||
const { api } = _converse;
|
|
||||||
let sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
|
||||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
|
||||||
let view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(3);
|
|
||||||
|
|
||||||
// Check in reverse order that we requested all three lists
|
|
||||||
const owner_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(owner_iq)).toBe(
|
|
||||||
`<iq id="${owner_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
const admin_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(admin_iq)).toBe(
|
|
||||||
`<iq id="${admin_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
const member_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(member_iq)).toBe(
|
|
||||||
`<iq id="${member_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
view.close();
|
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
api.settings.set('muc_fetch_members', false);
|
|
||||||
await mock.openAndEnterChatRoom(_converse, 'orchard@montague.lit', 'romeo');
|
|
||||||
view = _converse.chatboxviews.get('orchard@montague.lit');
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(0);
|
|
||||||
await view.close();
|
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
api.settings.set('muc_fetch_members', ['admin']);
|
|
||||||
await mock.openAndEnterChatRoom(_converse, 'courtyard@montague.lit', 'romeo');
|
|
||||||
view = _converse.chatboxviews.get('courtyard@montague.lit');
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(1);
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation="admin"]')).length).toBe(1);
|
|
||||||
view.close();
|
|
||||||
|
|
||||||
_converse.connection.IQ_stanzas = [];
|
|
||||||
sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
api.settings.set('muc_fetch_members', ['owner']);
|
|
||||||
await mock.openAndEnterChatRoom(_converse, 'garden@montague.lit', 'romeo');
|
|
||||||
view = _converse.chatboxviews.get('garden@montague.lit');
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation]')).length).toBe(1);
|
|
||||||
expect(sent_IQs.filter(iq => iq.querySelector('query item[affiliation="owner"]')).length).toBe(1);
|
|
||||||
view.close();
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("when fetching the member lists", function () {
|
|
||||||
|
|
||||||
it("gracefully handles being forbidden from fetching the lists for certain affiliations",
|
|
||||||
mock.initConverse([], {'muc_fetch_members': true}, async function (_converse) {
|
|
||||||
|
|
||||||
const sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
const muc_jid = 'lounge@montague.lit';
|
|
||||||
const features = [
|
|
||||||
'http://jabber.org/protocol/muc',
|
|
||||||
'jabber:iq:register',
|
|
||||||
'muc_hidden',
|
|
||||||
'muc_membersonly',
|
|
||||||
'muc_passwordprotected',
|
|
||||||
Strophe.NS.MAM,
|
|
||||||
Strophe.NS.SID
|
|
||||||
];
|
|
||||||
const nick = 'romeo';
|
|
||||||
await _converse.api.rooms.open(muc_jid);
|
|
||||||
await mock.getRoomFeatures(_converse, muc_jid, features);
|
|
||||||
await mock.waitForReservedNick(_converse, muc_jid, nick);
|
|
||||||
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));
|
|
||||||
|
|
||||||
// Check in reverse order that we requested all three lists
|
|
||||||
const owner_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(owner_iq)).toBe(
|
|
||||||
`<iq id="${owner_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
const admin_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(admin_iq)).toBe(
|
|
||||||
`<iq id="${admin_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
const member_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(member_iq)).toBe(
|
|
||||||
`<iq id="${member_iq.getAttribute('id')}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
// It might be that the user is not allowed to fetch certain lists.
|
|
||||||
let err_stanza = u.toStanza(
|
|
||||||
`<iq xmlns="jabber:client" type="error" to="${_converse.jid}" from="${muc_jid}" id="${admin_iq.getAttribute('id')}">
|
|
||||||
<error type="auth"><forbidden xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
|
|
||||||
</iq>`);
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(err_stanza));
|
|
||||||
|
|
||||||
err_stanza = u.toStanza(
|
|
||||||
`<iq xmlns="jabber:client" type="error" to="${_converse.jid}" from="${muc_jid}" id="${owner_iq.getAttribute('id')}">
|
|
||||||
<error type="auth"><forbidden xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
|
|
||||||
</iq>`);
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(err_stanza));
|
|
||||||
|
|
||||||
// Now the service sends the member lists to the user
|
|
||||||
const member_list_stanza = $iq({
|
|
||||||
'from': muc_jid,
|
|
||||||
'id': member_iq.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'type': 'result'
|
|
||||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'member',
|
|
||||||
'jid': 'hag66@shakespeare.lit',
|
|
||||||
'nick': 'thirdwitch',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(member_list_stanza));
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.model.occupants.length > 1);
|
|
||||||
expect(view.model.occupants.length).toBe(2);
|
|
||||||
// The existing owner occupant should not have their
|
|
||||||
// affiliation removed due to the owner list
|
|
||||||
// not being returned (forbidden err).
|
|
||||||
expect(view.model.occupants.findWhere({'jid': _converse.bare_jid}).get('affiliation')).toBe('owner');
|
|
||||||
expect(view.model.occupants.findWhere({'jid': 'hag66@shakespeare.lit'}).get('affiliation')).toBe('member');
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("topic", function () {
|
describe("topic", function () {
|
||||||
|
|
||||||
it("is shown the header", mock.initConverse([], {}, async function (_converse) {
|
it("is shown the header", mock.initConverse([], {}, async function (_converse) {
|
||||||
|
@ -3826,150 +3681,6 @@ describe("Groupchats", function () {
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Someone being invited to a groupchat", function () {
|
|
||||||
|
|
||||||
it("will first be added to the member list if the groupchat is members only",
|
|
||||||
mock.initConverse(['chatBoxesFetched'], {}, async function (_converse) {
|
|
||||||
|
|
||||||
await mock.waitForRoster(_converse, 'current', 0);
|
|
||||||
spyOn(_converse.ChatRoomOccupants.prototype, 'fetchMembers').and.callThrough();
|
|
||||||
const sent_IQs = _converse.connection.IQ_stanzas;
|
|
||||||
const muc_jid = 'coven@chat.shakespeare.lit';
|
|
||||||
const nick = 'romeo';
|
|
||||||
const room_creation_promise = _converse.api.rooms.open(muc_jid, {nick});
|
|
||||||
|
|
||||||
// Check that the groupchat queried for the features.
|
|
||||||
let stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/disco#info"]`)).pop());
|
|
||||||
expect(Strophe.serialize(stanza)).toBe(
|
|
||||||
`<iq from="romeo@montague.lit/orchard" id="${stanza.getAttribute("id")}" to="${muc_jid}" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/disco#info"/>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
// State that the chat is members-only via the features IQ
|
|
||||||
const view = _converse.chatboxviews.get(muc_jid);
|
|
||||||
const features_stanza = $iq({
|
|
||||||
from: 'coven@chat.shakespeare.lit',
|
|
||||||
'id': stanza.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/desktop',
|
|
||||||
'type': 'result'
|
|
||||||
})
|
|
||||||
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
|
||||||
.c('identity', {
|
|
||||||
'category': 'conference',
|
|
||||||
'name': 'A Dark Cave',
|
|
||||||
'type': 'text'
|
|
||||||
}).up()
|
|
||||||
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
|
||||||
.c('feature', {'var': 'muc_hidden'}).up()
|
|
||||||
.c('feature', {'var': 'muc_temporary'}).up()
|
|
||||||
.c('feature', {'var': 'muc_membersonly'}).up();
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(features_stanza));
|
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
|
||||||
await u.waitUntil(() => sent_stanzas.filter(s => s.matches(`presence[to="${muc_jid}/${nick}"]`)).pop());
|
|
||||||
expect(view.model.features.get('membersonly')).toBeTruthy();
|
|
||||||
|
|
||||||
await room_creation_promise;
|
|
||||||
await mock.createContacts(_converse, 'current');
|
|
||||||
|
|
||||||
let sent_stanza, sent_id;
|
|
||||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
|
||||||
if (stanza.nodeName === 'message') {
|
|
||||||
sent_id = stanza.getAttribute('id');
|
|
||||||
sent_stanza = stanza;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const invitee_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
|
||||||
const reason = "Please join this groupchat";
|
|
||||||
view.model.directInvite(invitee_jid, reason);
|
|
||||||
|
|
||||||
// Check in reverse order that we requested all three lists
|
|
||||||
const owner_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(owner_iq)).toBe(
|
|
||||||
`<iq id="${owner_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
const admin_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(admin_iq)).toBe(
|
|
||||||
`<iq id="${admin_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="admin"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
const member_iq = sent_IQs.pop();
|
|
||||||
expect(Strophe.serialize(member_iq)).toBe(
|
|
||||||
`<iq id="${member_iq.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="member"/></query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
// Now the service sends the member lists to the user
|
|
||||||
const member_list_stanza = $iq({
|
|
||||||
'from': 'coven@chat.shakespeare.lit',
|
|
||||||
'id': member_iq.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'type': 'result'
|
|
||||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'member',
|
|
||||||
'jid': 'hag66@shakespeare.lit',
|
|
||||||
'nick': 'thirdwitch',
|
|
||||||
'role': 'participant'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(member_list_stanza));
|
|
||||||
|
|
||||||
const admin_list_stanza = $iq({
|
|
||||||
'from': 'coven@chat.shakespeare.lit',
|
|
||||||
'id': admin_iq.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'type': 'result'
|
|
||||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'admin',
|
|
||||||
'jid': 'wiccarocks@shakespeare.lit',
|
|
||||||
'nick': 'secondwitch'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(admin_list_stanza));
|
|
||||||
|
|
||||||
const owner_list_stanza = $iq({
|
|
||||||
'from': 'coven@chat.shakespeare.lit',
|
|
||||||
'id': owner_iq.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'type': 'result'
|
|
||||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
|
||||||
.c('item', {
|
|
||||||
'affiliation': 'owner',
|
|
||||||
'jid': 'crone1@shakespeare.lit',
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(owner_list_stanza));
|
|
||||||
|
|
||||||
// Converse puts the user on the member list
|
|
||||||
stanza = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq[to="${muc_jid}"] query[xmlns="http://jabber.org/protocol/muc#admin"]`)).pop());
|
|
||||||
expect(stanza.outerHTML,
|
|
||||||
`<iq id="${stanza.getAttribute('id')}" to="coven@chat.shakespeare.lit" type="set" xmlns="jabber:client">`+
|
|
||||||
`<query xmlns="http://jabber.org/protocol/muc#admin">`+
|
|
||||||
`<item affiliation="member" jid="${invitee_jid}">`+
|
|
||||||
`<reason>Please join this groupchat</reason>`+
|
|
||||||
`</item>`+
|
|
||||||
`</query>`+
|
|
||||||
`</iq>`);
|
|
||||||
|
|
||||||
const result = $iq({
|
|
||||||
'from': 'coven@chat.shakespeare.lit',
|
|
||||||
'id': stanza.getAttribute('id'),
|
|
||||||
'to': 'romeo@montague.lit/orchard',
|
|
||||||
'type': 'result'
|
|
||||||
});
|
|
||||||
_converse.connection._dataRecv(mock.createRequest(result));
|
|
||||||
|
|
||||||
await u.waitUntil(() => view.model.occupants.fetchMembers.calls.count());
|
|
||||||
|
|
||||||
// Finally check that the user gets invited.
|
|
||||||
expect(Strophe.serialize(sent_stanza)).toBe( // Strophe adds the xmlns attr (although not in spec)
|
|
||||||
`<message from="romeo@montague.lit/orchard" id="${sent_id}" to="${invitee_jid}" xmlns="jabber:client">`+
|
|
||||||
`<x jid="coven@chat.shakespeare.lit" reason="Please join this groupchat" xmlns="jabber:x:conference"/>`+
|
|
||||||
`</message>`
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("The affiliations delta", function () {
|
describe("The affiliations delta", function () {
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ async function returnMemberLists (_converse, muc_jid, members=[], affiliations=[
|
||||||
return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
|
return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function receiveOwnMUCPresence (_converse, muc_jid, nick) {
|
async function receiveOwnMUCPresence (_converse, muc_jid, nick, affiliation='owner', role='moderator') {
|
||||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||||
await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
|
await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
|
||||||
const presence = $pres({
|
const presence = $pres({
|
||||||
|
@ -291,17 +291,23 @@ async function receiveOwnMUCPresence (_converse, muc_jid, nick) {
|
||||||
from: `${muc_jid}/${nick}`,
|
from: `${muc_jid}/${nick}`,
|
||||||
id: u.getUniqueId()
|
id: u.getUniqueId()
|
||||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||||
.c('item').attrs({
|
.c('item').attrs({ affiliation, role, 'jid': _converse.bare_jid }).up()
|
||||||
affiliation: 'owner',
|
|
||||||
jid: _converse.bare_jid,
|
|
||||||
role: 'moderator'
|
|
||||||
}).up()
|
|
||||||
.c('status').attrs({code:'110'});
|
.c('status').attrs({code:'110'});
|
||||||
_converse.connection._dataRecv(createRequest(presence));
|
_converse.connection._dataRecv(createRequest(presence));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function openAndEnterChatRoom (_converse, muc_jid, nick, features=[], members=[], force_open=true, settings={}) {
|
async function openAndEnterChatRoom (
|
||||||
|
_converse,
|
||||||
|
muc_jid,
|
||||||
|
nick,
|
||||||
|
features=[],
|
||||||
|
members=[],
|
||||||
|
force_open=true,
|
||||||
|
settings={},
|
||||||
|
own_affiliation='owner',
|
||||||
|
own_role='moderator',
|
||||||
|
) {
|
||||||
const { api } = _converse;
|
const { api } = _converse;
|
||||||
muc_jid = muc_jid.toLowerCase();
|
muc_jid = muc_jid.toLowerCase();
|
||||||
const room_creation_promise = api.rooms.open(muc_jid, settings, force_open);
|
const room_creation_promise = api.rooms.open(muc_jid, settings, force_open);
|
||||||
|
@ -310,7 +316,7 @@ async function openAndEnterChatRoom (_converse, muc_jid, nick, features=[], memb
|
||||||
// The user has just entered the room (because join was called)
|
// The user has just entered the room (because join was called)
|
||||||
// and receives their own presence from the server.
|
// and receives their own presence from the server.
|
||||||
// See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
|
// See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
|
||||||
await receiveOwnMUCPresence(_converse, muc_jid, nick);
|
await receiveOwnMUCPresence(_converse, muc_jid, nick, own_affiliation, own_role);
|
||||||
|
|
||||||
await room_creation_promise;
|
await room_creation_promise;
|
||||||
const model = _converse.chatboxes.get(muc_jid);
|
const model = _converse.chatboxes.get(muc_jid);
|
||||||
|
@ -318,7 +324,10 @@ async function openAndEnterChatRoom (_converse, muc_jid, nick, features=[], memb
|
||||||
|
|
||||||
const affs = api.settings.get('muc_fetch_members');
|
const affs = api.settings.get('muc_fetch_members');
|
||||||
const all_affiliations = Array.isArray(affs) ? affs : (affs ? ['member', 'admin', 'owner'] : []);
|
const all_affiliations = Array.isArray(affs) ? affs : (affs ? ['member', 'admin', 'owner'] : []);
|
||||||
await returnMemberLists(_converse, muc_jid, members, all_affiliations);
|
|
||||||
|
if (['member', 'admin', 'owner'].includes(own_affiliation)) {
|
||||||
|
await returnMemberLists(_converse, muc_jid, members, all_affiliations);
|
||||||
|
}
|
||||||
await model.messages.fetched;
|
await model.messages.fetched;
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user