Commit 376c50fb authored by JC Brand's avatar JC Brand

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

parent 088eb03b
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
disconnection or reconnection events. [jcbrand] disconnection or reconnection events. [jcbrand]
- Optimize fetching of MAM messages (in some cases happened on each page load). [jcbrand] - Optimize fetching of MAM messages (in some cases happened on each page load). [jcbrand]
- Fix empty controlbox toggle after disconnect. [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) ## 2.0.3 (2016-11-30)
- #735 Room configuration button not visible. [jcbrand] - #735 Room configuration button not visible. [jcbrand]
......
...@@ -907,7 +907,7 @@ ...@@ -907,7 +907,7 @@
expect($occupants.children().first(0).text()).toBe("newnick"); 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 sent_IQ, IQ_id;
var sendIQ = converse.connection.sendIQ; var sendIQ = converse.connection.sendIQ;
spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) { spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
...@@ -955,21 +955,21 @@ ...@@ -955,21 +955,21 @@
'type': 'text' 'type': 'text'
}).up() }).up()
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up() .c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'passwordprotected'}).up() .c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'hidden'}).up() .c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'temporary'}).up() .c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'open'}).up() .c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'unmoderated'}).up() .c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'nonanonymous'}); .c('feature', {'var': 'muc_nonanonymous'});
converse.connection._dataRecv(test_utils.createRequest(features_stanza)); converse.connection._dataRecv(test_utils.createRequest(features_stanza));
var view = converse.chatboxviews.get('coven@chat.shakespeare.lit'); var view = converse.chatboxviews.get('coven@chat.shakespeare.lit');
expect(view.model.get('passwordprotected')).toBe('true'); expect(view.model.get('passwordprotected')).toBe(true);
expect(view.model.get('hidden')).toBe('true'); expect(view.model.get('hidden')).toBe(true);
expect(view.model.get('temporary')).toBe('true'); expect(view.model.get('temporary')).toBe(true);
expect(view.model.get('open')).toBe('true'); expect(view.model.get('open')).toBe(true);
expect(view.model.get('unmoderated')).toBe('true'); expect(view.model.get('unmoderated')).toBe(true);
expect(view.model.get('nonanonymous')).toBe('true'); expect(view.model.get('nonanonymous')).toBe(true);
})); }));
it("indicates when a room is no longer anonymous", mock.initConverse(function (converse) { it("indicates when a room is no longer anonymous", mock.initConverse(function (converse) {
...@@ -1398,5 +1398,73 @@ ...@@ -1398,5 +1398,73 @@
expect(view.$el.find('.chatroom-body p:last').text()).toBe("This room has reached its maximum number of occupants"); 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>"
);
}));
});
}); });
})); }));
...@@ -1182,6 +1182,7 @@ ...@@ -1182,6 +1182,7 @@
chat_status = $presence.find('show').text() || 'online', chat_status = $presence.find('show').text() || 'online',
status_message = $presence.find('status'), status_message = $presence.find('status'),
contact = this.get(bare_jid); contact = this.get(bare_jid);
if (this.isSelf(bare_jid)) { if (this.isSelf(bare_jid)) {
if ((converse.connection.jid !== jid) && if ((converse.connection.jid !== jid) &&
(presence_type !== 'unavailable') && (presence_type !== 'unavailable') &&
......
...@@ -494,6 +494,29 @@ ...@@ -494,6 +494,29 @@
this.insertIntoTextArea(ev.target.textContent); 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) { directInvite: function (recipient, reason) {
/* Send a direct invitation as per XEP-0249 /* Send a direct invitation as per XEP-0249
* *
...@@ -501,6 +524,15 @@ ...@@ -501,6 +524,15 @@
* (String) recipient - JID of the person being invited * (String) recipient - JID of the person being invited
* (String) reason - Optional reason for the invitation * (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 = { var attrs = {
'xmlns': 'jabber:x:conference', 'xmlns': 'jabber:x:conference',
'jid': this.model.get('jid') 'jid': this.model.get('jid')
...@@ -1082,7 +1114,7 @@ ...@@ -1082,7 +1114,7 @@
var that = this; var that = this;
converse.connection.disco.info(this.model.get('jid'), null, converse.connection.disco.info(this.model.get('jid'), null,
function (iq) { function (iq) {
/* /*
* See http://xmpp.org/extensions/xep-0045.html#disco-roominfo * See http://xmpp.org/extensions/xep-0045.html#disco-roominfo
* *
* <identity * <identity
...@@ -1514,7 +1546,7 @@ ...@@ -1514,7 +1546,7 @@
this.model.save('connection_status', Strophe.Status.DISCONNECTED); this.model.save('connection_status', Strophe.Status.DISCONNECTED);
this.showErrorMessage(pres); this.showErrorMessage(pres);
return true; return true;
} }
var show_status_messages = true; var show_status_messages = true;
var is_self = pres.querySelector("status[code='110']"); var is_self = pres.querySelector("status[code='110']");
var new_room = pres.querySelector("status[code='201']"); var new_room = pres.querySelector("status[code='201']");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment