When inviting to a members-only room, first add to user to the member-list

This commit is contained in:
JC Brand 2016-12-05 10:50:01 +00:00
parent 088eb03b54
commit 376c50fbc8
4 changed files with 118 additions and 15 deletions

View File

@ -10,6 +10,8 @@
disconnection or reconnection events. [jcbrand]
- Optimize fetching of MAM messages (in some cases happened on each page load). [jcbrand]
- Fix empty controlbox toggle after disconnect. [jcbrand]
- When inviting someone to a members-only room, first add them to the member
list. [jcbrand]
## 2.0.3 (2016-11-30)
- #735 Room configuration button not visible. [jcbrand]

View File

@ -907,7 +907,7 @@
expect($occupants.children().first(0).text()).toBe("newnick");
}));
if("queries for the room information before attempting to join the user", mock.initConverse(function (converse) {
it("queries for the room information before attempting to join the user", mock.initConverse(function (converse) {
var sent_IQ, IQ_id;
var sendIQ = converse.connection.sendIQ;
spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
@ -955,21 +955,21 @@
'type': 'text'
}).up()
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'passwordprotected'}).up()
.c('feature', {'var': 'hidden'}).up()
.c('feature', {'var': 'temporary'}).up()
.c('feature', {'var': 'open'}).up()
.c('feature', {'var': 'unmoderated'}).up()
.c('feature', {'var': 'nonanonymous'});
.c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'muc_nonanonymous'});
converse.connection._dataRecv(test_utils.createRequest(features_stanza));
var view = converse.chatboxviews.get('coven@chat.shakespeare.lit');
expect(view.model.get('passwordprotected')).toBe('true');
expect(view.model.get('hidden')).toBe('true');
expect(view.model.get('temporary')).toBe('true');
expect(view.model.get('open')).toBe('true');
expect(view.model.get('unmoderated')).toBe('true');
expect(view.model.get('nonanonymous')).toBe('true');
expect(view.model.get('passwordprotected')).toBe(true);
expect(view.model.get('hidden')).toBe(true);
expect(view.model.get('temporary')).toBe(true);
expect(view.model.get('open')).toBe(true);
expect(view.model.get('unmoderated')).toBe(true);
expect(view.model.get('nonanonymous')).toBe(true);
}));
it("indicates when a room is no longer anonymous", mock.initConverse(function (converse) {
@ -1398,5 +1398,73 @@
expect(view.$el.find('.chatroom-body p:last').text()).toBe("This room has reached its maximum number of occupants");
}));
});
describe("Someone being invited to a chat room", function () {
it("will first be added to the member list if the chat room is members only", mock.initConverse(function (converse) {
var sent_IQ, IQ_id;
var sendIQ = converse.connection.sendIQ;
spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
sent_IQ = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback);
});
test_utils.openChatRoom(converse, 'coven', 'chat.shakespeare.lit', 'dummy');
// State that the chat is members-only via the features IQ
var features_stanza = $iq({
from: 'coven@chat.shakespeare.lit',
'id': IQ_id,
'to': 'dummy@localhost/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(test_utils.createRequest(features_stanza));
var view = converse.chatboxviews.get('coven@chat.shakespeare.lit');
expect(view.model.get('membersonly')).toBeTruthy();
spyOn(view, 'setMemberList').andCallThrough();
test_utils.createContacts(converse, 'current');
var sent_stanza,
sent_id;
spyOn(converse.connection, 'send').andCallFake(function (stanza) {
if (stanza.nodeTree && stanza.nodeTree.nodeName === 'message') {
sent_id = stanza.nodeTree.getAttribute('id');
sent_stanza = stanza;
}
});
var name = mock.cur_names[0];
var invitee_jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
var reason = "Please join this chat room";
view.directInvite(invitee_jid, reason);
expect(sent_IQ.toLocaleString()).toBe(
"<iq to='coven@chat.shakespeare.lit' type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
"<item affiliation='member' jid='"+invitee_jid+"'/>"+
"</query>"+
"</iq>");
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
"<message from='dummy@localhost/resource' to='"+invitee_jid+"' id='"+sent_id+"' xmlns='jabber:client'>"+
"<x xmlns='jabber:x:conference' jid='coven@chat.shakespeare.lit' reason='Please join this chat room'/>"+
"</message>"
);
}));
});
});
}));

View File

@ -1182,6 +1182,7 @@
chat_status = $presence.find('show').text() || 'online',
status_message = $presence.find('status'),
contact = this.get(bare_jid);
if (this.isSelf(bare_jid)) {
if ((converse.connection.jid !== jid) &&
(presence_type !== 'unavailable') &&

View File

@ -494,6 +494,29 @@
this.insertIntoTextArea(ev.target.textContent);
},
setMemberList: function (members, onSuccess, onError) {
/* Send an IQ stanza to the server to modify the
* member-list of this room.
*
* See: http://xmpp.org/extensions/xep-0045.html#modifymember
*
* Parameters:
* (Array) members: An array of member objects, containing
* the JID and affiliation of each.
* (Function) onSuccess: callback for a succesful response
* (Function) onError: callback for an error response
*/
var iq = $iq({to: this.model.get('jid'), type: "set"})
.c("query", {xmlns: Strophe.NS.MUC_ADMIN});
_.each(members, function (member) {
iq.c("item", {
'affiliation': member.affiliation,
'jid': member.jid
});
});
return converse.connection.sendIQ(iq, onSuccess, onError);
},
directInvite: function (recipient, reason) {
/* Send a direct invitation as per XEP-0249
*
@ -501,6 +524,15 @@
* (String) recipient - JID of the person being invited
* (String) reason - Optional reason for the invitation
*/
if (this.model.get('membersonly')) {
// When inviting to a members-only room, we first add
// the person to the member list, otherwise they won't
// be able to join.
this.setMemberList([{
'jid': recipient,
'affiliation': 'member'
}]);
}
var attrs = {
'xmlns': 'jabber:x:conference',
'jid': this.model.get('jid')
@ -1082,7 +1114,7 @@
var that = this;
converse.connection.disco.info(this.model.get('jid'), null,
function (iq) {
/*
/*
* See http://xmpp.org/extensions/xep-0045.html#disco-roominfo
*
* <identity
@ -1514,7 +1546,7 @@
this.model.save('connection_status', Strophe.Status.DISCONNECTED);
this.showErrorMessage(pres);
return true;
}
}
var show_status_messages = true;
var is_self = pres.querySelector("status[code='110']");
var new_room = pres.querySelector("status[code='201']");