In the menu, only show allowed commands
This commit is contained in:
parent
3bd9e09fd7
commit
c72dc74022
@ -21,8 +21,9 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"lodash/prefer-lodash-method": [2, {
|
"lodash/prefer-lodash-method": [2, {
|
||||||
"ignoreMethods": [
|
"ignoreMethods": [
|
||||||
"keys", "find", "endsWith", "startsWith", "filter", "reduce", "isArray", "create",
|
"every", "keys", "find", "endsWith", "startsWith", "filter", "reduce", "isArray",
|
||||||
"map", "replace", "toLower", "split", "trim", "forEach", "toUpperCase", "includes"
|
"create", "map", "replace", "some", "toLower", "split", "trim", "forEach",
|
||||||
|
"toUpperCase", "includes"
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
"lodash/prefer-invoke-map": "off",
|
"lodash/prefer-invoke-map": "off",
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
- Take roster nickname into consideration when rendering messages and chat headings.
|
- Take roster nickname into consideration when rendering messages and chat headings.
|
||||||
- Hide the textarea when a user is muted in a groupchat.
|
- Hide the textarea when a user is muted in a groupchat.
|
||||||
- Don't restore a BOSH session without knowing the JID
|
- Don't restore a BOSH session without knowing the JID
|
||||||
|
- In the `/help` menu, only show allowed commands
|
||||||
- #1296: `embedded` view mode shows `chatbox-navback` arrow in header
|
- #1296: `embedded` view mode shows `chatbox-navback` arrow in header
|
||||||
- #1532: Converse reloads on enter pressed in the filter box
|
- #1532: Converse reloads on enter pressed in the filter box
|
||||||
|
|
||||||
|
86
dist/converse.js
vendored
86
dist/converse.js
vendored
@ -53468,6 +53468,10 @@ const _converse$env = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_
|
|||||||
$pres = _converse$env.$pres;
|
$pres = _converse$env.$pres;
|
||||||
const u = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].env.utils;
|
const u = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].env.utils;
|
||||||
const AFFILIATION_CHANGE_COMANDS = ['admin', 'ban', 'owner', 'member', 'revoke'];
|
const AFFILIATION_CHANGE_COMANDS = ['admin', 'ban', 'owner', 'member', 'revoke'];
|
||||||
|
const OWNER_COMMANDS = ['owner'];
|
||||||
|
const ADMIN_COMMANDS = ['admin', 'ban', 'deop', 'destroy', 'member', 'op', 'revoke'];
|
||||||
|
const MODERATOR_COMMANDS = ['kick', 'mute', 'voice'];
|
||||||
|
const VISITOR_COMMANDS = ['nick'];
|
||||||
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins.add('converse-muc-views', {
|
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins.add('converse-muc-views', {
|
||||||
/* Dependencies are other plugins which might be
|
/* Dependencies are other plugins which might be
|
||||||
* overridden or relied upon, and therefore need to be loaded before
|
* overridden or relied upon, and therefore need to be loaded before
|
||||||
@ -54385,26 +54389,40 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
||||||
},
|
},
|
||||||
|
|
||||||
verifyRoles(roles) {
|
verifyRoles(roles, occupant) {
|
||||||
const me = this.model.occupants.findWhere({
|
let show_error = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
||||||
|
|
||||||
|
if (!occupant) {
|
||||||
|
occupant = this.model.occupants.findWhere({
|
||||||
'jid': _converse.bare_jid
|
'jid': _converse.bare_jid
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!_.includes(roles, me.get('role'))) {
|
if (!_.includes(roles, occupant.get('role'))) {
|
||||||
|
if (show_error) {
|
||||||
this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'));
|
this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'));
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
verifyAffiliations(affiliations) {
|
verifyAffiliations(affiliations, occupant) {
|
||||||
const me = this.model.occupants.findWhere({
|
let show_error = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
||||||
|
|
||||||
|
if (!occupant) {
|
||||||
|
occupant = this.model.occupants.findWhere({
|
||||||
'jid': _converse.bare_jid
|
'jid': _converse.bare_jid
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!_.includes(affiliations, me.get('affiliation'))) {
|
if (!_.includes(affiliations, occupant.get('affiliation'))) {
|
||||||
|
if (show_error) {
|
||||||
this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'));
|
this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'));
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54454,6 +54472,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'admin':
|
case 'admin':
|
||||||
|
{
|
||||||
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54463,9 +54482,11 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
'reason': args[1]
|
'reason': args[1]
|
||||||
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'ban':
|
case 'ban':
|
||||||
if (!this.verifyAffiliations(['owner', 'admin']) || !this.validateRoleChangeCommand(command, args)) {
|
{
|
||||||
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54474,42 +54495,81 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
'reason': args[1]
|
'reason': args[1]
|
||||||
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'deop':
|
case 'deop':
|
||||||
|
{
|
||||||
|
// FIXME: /deop only applies to setting a moderators
|
||||||
|
// role to "participant" (which only admin/owner can
|
||||||
|
// do). Moderators can however set non-moderator's role
|
||||||
|
// to participant (e.g. visitor => participant).
|
||||||
|
// Currently we don't distinguish between these two
|
||||||
|
// cases.
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyRole(this.model.get('jid'), args[0], 'participant', args[1], undefined, this.onCommandError.bind(this));
|
this.modifyRole(this.model.get('jid'), args[0], 'participant', args[1], undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'destroy':
|
case 'destroy':
|
||||||
|
{
|
||||||
if (!this.verifyAffiliations(['owner'])) {
|
if (!this.verifyAffiliations(['owner'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.destroy(this.model.get('jid'), args[0]).then(() => this.close()).catch(e => this.onCommandError(e));
|
this.destroy(this.model.get('jid'), args[0]).then(() => this.close()).catch(e => this.onCommandError(e));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'help':
|
case 'help':
|
||||||
this.showHelpMessages(_.filter([`<strong>/admin</strong>: ${__("Change user's affiliation to admin")}`, `<strong>/ban</strong>: ${__('Ban user from groupchat')}`, `<strong>/clear</strong>: ${__('Remove messages')}`, `<strong>/deop</strong>: ${__('Change user role to participant')}`, `<strong>/destroy</strong>: ${__('Remove this groupchat')}`, `<strong>/help</strong>: ${__('Show this menu')}`, `<strong>/kick</strong>: ${__('Kick user from groupchat')}`, `<strong>/me</strong>: ${__('Write in 3rd person')}`, `<strong>/member</strong>: ${__('Grant membership to a user')}`, `<strong>/mute</strong>: ${__("Remove user's ability to post messages")}`, `<strong>/nick</strong>: ${__('Change your nickname')}`, `<strong>/op</strong>: ${__('Grant moderator role to user')}`, `<strong>/owner</strong>: ${__('Grant ownership of this groupchat')}`, `<strong>/register</strong>: ${__("Register a nickname for this groupchat")}`, `<strong>/revoke</strong>: ${__("Revoke user's membership")}`, `<strong>/subject</strong>: ${__('Set groupchat subject')}`, `<strong>/topic</strong>: ${__('Set groupchat subject (alias for /subject)')}`, `<strong>/voice</strong>: ${__('Allow muted user to post messages')}`], line => _.every(disabled_commands, element => !line.startsWith(element + '<', 9))));
|
{
|
||||||
|
// FIXME: The availability of some of these commands
|
||||||
|
// depend on the MUCs configuration (e.g. whether it's
|
||||||
|
// moderated or not). We need to take that into
|
||||||
|
// consideration.
|
||||||
|
let allowed_commands = ['clear', 'help', 'me', 'nick', 'subject', 'topic', 'register'];
|
||||||
|
const occupant = this.model.occupants.findWhere({
|
||||||
|
'jid': _converse.bare_jid
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.verifyAffiliations('owner', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(OWNER_COMMANDS).concat(ADMIN_COMMANDS);
|
||||||
|
} else if (this.verifyAffiliations('admin', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(ADMIN_COMMANDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.verifyRoles('moderator', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(MODERATOR_COMMANDS).concat(VISITOR_COMMANDS);
|
||||||
|
} else if (!this.verifyRoles(['visitor', 'participant', 'moderator'], occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(VISITOR_COMMANDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showHelpMessages([`<strong>${__("You can run the following commands")}</strong>`]);
|
||||||
|
this.showHelpMessages([`<strong>/admin</strong>: ${__("Change user's affiliation to admin")}`, `<strong>/ban</strong>: ${__('Ban user from groupchat')}`, `<strong>/clear</strong>: ${__('Clear the chat area')}`, `<strong>/deop</strong>: ${__('Change user role to participant')}`, `<strong>/destroy</strong>: ${__('Remove this groupchat')}`, `<strong>/help</strong>: ${__('Show this menu')}`, `<strong>/kick</strong>: ${__('Kick user from groupchat')}`, `<strong>/me</strong>: ${__('Write in 3rd person')}`, `<strong>/member</strong>: ${__('Grant membership to a user')}`, `<strong>/mute</strong>: ${__("Remove user's ability to post messages")}`, `<strong>/nick</strong>: ${__('Change your nickname')}`, `<strong>/op</strong>: ${__('Grant moderator role to user')}`, `<strong>/owner</strong>: ${__('Grant ownership of this groupchat')}`, `<strong>/register</strong>: ${__("Register your nickname")}`, `<strong>/revoke</strong>: ${__("Revoke user's membership")}`, `<strong>/subject</strong>: ${__('Set groupchat subject')}`, `<strong>/topic</strong>: ${__('Set groupchat subject (alias for /subject)')}`, `<strong>/voice</strong>: ${__('Allow muted user to post messages')}`].filter(line => disabled_commands.every(c => !line.startsWith(c + '<', 9))).filter(line => allowed_commands.some(c => line.startsWith(c + '<', 9))));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'kick':
|
case 'kick':
|
||||||
|
{
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyRole(this.model.get('jid'), args[0], 'none', args[1], undefined, this.onCommandError.bind(this));
|
this.modifyRole(this.model.get('jid'), args[0], 'none', args[1], undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'mute':
|
case 'mute':
|
||||||
|
{
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyRole(this.model.get('jid'), args[0], 'visitor', args[1], undefined, this.onCommandError.bind(this));
|
this.modifyRole(this.model.get('jid'), args[0], 'visitor', args[1], undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'member':
|
case 'member':
|
||||||
{
|
{
|
||||||
@ -54536,6 +54596,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'nick':
|
case 'nick':
|
||||||
|
{
|
||||||
if (!this.verifyRoles(['visitor', 'participant', 'moderator'])) {
|
if (!this.verifyRoles(['visitor', 'participant', 'moderator'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54547,6 +54608,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
}).tree());
|
}).tree());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'owner':
|
case 'owner':
|
||||||
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
@ -54560,14 +54622,17 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'op':
|
case 'op':
|
||||||
|
{
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyRole(this.model.get('jid'), args[0], 'moderator', args[1], undefined, this.onCommandError.bind(this));
|
this.modifyRole(this.model.get('jid'), args[0], 'moderator', args[1], undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'register':
|
case 'register':
|
||||||
|
{
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
this.showErrorMessage(__('Error: invalid number of arguments'));
|
this.showErrorMessage(__('Error: invalid number of arguments'));
|
||||||
} else {
|
} else {
|
||||||
@ -54577,8 +54642,10 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'revoke':
|
case 'revoke':
|
||||||
|
{
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54588,6 +54655,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
'reason': args[1]
|
'reason': args[1]
|
||||||
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
}]).then(() => this.model.occupants.fetchMembers(), err => this.onCommandError(err));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'topic':
|
case 'topic':
|
||||||
case 'subject':
|
case 'subject':
|
||||||
@ -54603,12 +54671,14 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'voice':
|
case 'voice':
|
||||||
|
{
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyRole(this.model.get('jid'), args[0], 'participant', args[1], undefined, this.onCommandError.bind(this));
|
this.modifyRole(this.model.get('jid'), args[0], 'participant', args[1], undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
|
return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
|
||||||
|
67
spec/muc.js
67
spec/muc.js
@ -1781,9 +1781,7 @@
|
|||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
test_utils.createContacts(_converse, 'current'); // We need roster contacts, who can invite us
|
test_utils.createContacts(_converse, 'current'); // We need roster contacts, who can invite us
|
||||||
spyOn(window, 'confirm').and.callFake(function () {
|
spyOn(window, 'confirm').and.callFake(() => true);
|
||||||
return true;
|
|
||||||
});
|
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||||
view.close(); // Hack, otherwise we have to mock stanzas.
|
view.close(); // Hack, otherwise we have to mock stanzas.
|
||||||
@ -2550,23 +2548,24 @@
|
|||||||
null, ['rosterGroupsFetched'], {},
|
null, ['rosterGroupsFetched'], {},
|
||||||
async function (done, _converse) {
|
async function (done, _converse) {
|
||||||
|
|
||||||
|
spyOn(window, 'confirm').and.callFake(() => true);
|
||||||
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy');
|
||||||
const view = _converse.chatboxviews.get('lounge@localhost');
|
const view = _converse.chatboxviews.get('lounge@localhost');
|
||||||
var textarea = view.el.querySelector('.chat-textarea');
|
const textarea = view.el.querySelector('.chat-textarea');
|
||||||
textarea.value = '/help This is the groupchat subject';
|
textarea.value = '/clear';
|
||||||
view.keyPressed({
|
|
||||||
target: textarea,
|
|
||||||
preventDefault: _.noop,
|
|
||||||
keyCode: 13
|
|
||||||
});
|
|
||||||
|
|
||||||
const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
|
const enter = { 'target': textarea, 'preventDefault': _.noop, 'keyCode': 13 };
|
||||||
|
view.keyPressed(enter);
|
||||||
|
textarea.value = '/help';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
|
||||||
|
let info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
|
||||||
expect(info_messages.length).toBe(19);
|
expect(info_messages.length).toBe(19);
|
||||||
expect(info_messages.pop().textContent).toBe('/voice: Allow muted user to post messages');
|
expect(info_messages.pop().textContent).toBe('/voice: Allow muted user to post messages');
|
||||||
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)');
|
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)');
|
||||||
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject');
|
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject');
|
||||||
expect(info_messages.pop().textContent).toBe('/revoke: Revoke user\'s membership');
|
expect(info_messages.pop().textContent).toBe('/revoke: Revoke user\'s membership');
|
||||||
expect(info_messages.pop().textContent).toBe('/register: Register a nickname for this groupchat');
|
expect(info_messages.pop().textContent).toBe('/register: Register your nickname');
|
||||||
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat');
|
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user');
|
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user');
|
||||||
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname');
|
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname');
|
||||||
@ -2577,9 +2576,44 @@
|
|||||||
expect(info_messages.pop().textContent).toBe('/help: Show this menu');
|
expect(info_messages.pop().textContent).toBe('/help: Show this menu');
|
||||||
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat');
|
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant');
|
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant');
|
||||||
expect(info_messages.pop().textContent).toBe('/clear: Remove messages');
|
expect(info_messages.pop().textContent).toBe('/clear: Clear the chat area');
|
||||||
expect(info_messages.pop().textContent).toBe('/ban: Ban user from groupchat');
|
expect(info_messages.pop().textContent).toBe('/ban: Ban user from groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin');
|
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin');
|
||||||
|
expect(info_messages.pop().textContent).toBe('You can run the following commands');
|
||||||
|
|
||||||
|
const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||||
|
occupant.set('affiliation', 'admin');
|
||||||
|
textarea.value = '/clear';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
textarea.value = '/help';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
info_messages = sizzle('.chat-info', view.el).slice(1);
|
||||||
|
expect(info_messages.length).toBe(17);
|
||||||
|
let commands = info_messages.map(m => m.textContent.replace(/:.*$/, ''));
|
||||||
|
expect(commands).toEqual([
|
||||||
|
"/admin", "/ban", "/clear", "/deop", "/destroy",
|
||||||
|
"/help", "/kick", "/me", "/member", "/mute", "/nick",
|
||||||
|
"/op", "/register", "/revoke", "/subject", "/topic", "/voice"
|
||||||
|
]);
|
||||||
|
occupant.set('affiliation', 'member');
|
||||||
|
textarea.value = '/clear';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
textarea.value = '/help';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
info_messages = sizzle('.chat-info', view.el).slice(1);
|
||||||
|
expect(info_messages.length).toBe(10);
|
||||||
|
commands = info_messages.map(m => m.textContent.replace(/:.*$/, ''));
|
||||||
|
expect(commands).toEqual(["/clear", "/help", "/kick", "/me", "/mute", "/nick", "/register", "/subject", "/topic", "/voice"]);
|
||||||
|
|
||||||
|
occupant.set('role', 'participant');
|
||||||
|
textarea.value = '/clear';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
textarea.value = '/help';
|
||||||
|
view.keyPressed(enter);
|
||||||
|
info_messages = sizzle('.chat-info', view.el).slice(1);
|
||||||
|
expect(info_messages.length).toBe(7);
|
||||||
|
commands = info_messages.map(m => m.textContent.replace(/:.*$/, ''));
|
||||||
|
expect(commands).toEqual(["/clear", "/help", "/me", "/nick", "/register", "/subject", "/topic"]);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -2599,11 +2633,11 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
|
const info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
|
||||||
expect(info_messages.length).toBe(17);
|
expect(info_messages.length).toBe(18);
|
||||||
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)');
|
expect(info_messages.pop().textContent).toBe('/topic: Set groupchat subject (alias for /subject)');
|
||||||
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject');
|
expect(info_messages.pop().textContent).toBe('/subject: Set groupchat subject');
|
||||||
expect(info_messages.pop().textContent).toBe('/revoke: Revoke user\'s membership');
|
expect(info_messages.pop().textContent).toBe('/revoke: Revoke user\'s membership');
|
||||||
expect(info_messages.pop().textContent).toBe('/register: Register a nickname for this groupchat');
|
expect(info_messages.pop().textContent).toBe('/register: Register your nickname');
|
||||||
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat');
|
expect(info_messages.pop().textContent).toBe('/owner: Grant ownership of this groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user');
|
expect(info_messages.pop().textContent).toBe('/op: Grant moderator role to user');
|
||||||
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname');
|
expect(info_messages.pop().textContent).toBe('/nick: Change your nickname');
|
||||||
@ -2613,9 +2647,10 @@
|
|||||||
expect(info_messages.pop().textContent).toBe('/help: Show this menu');
|
expect(info_messages.pop().textContent).toBe('/help: Show this menu');
|
||||||
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat');
|
expect(info_messages.pop().textContent).toBe('/destroy: Remove this groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant');
|
expect(info_messages.pop().textContent).toBe('/deop: Change user role to participant');
|
||||||
expect(info_messages.pop().textContent).toBe('/clear: Remove messages');
|
expect(info_messages.pop().textContent).toBe('/clear: Clear the chat area');
|
||||||
expect(info_messages.pop().textContent).toBe('/ban: Ban user from groupchat');
|
expect(info_messages.pop().textContent).toBe('/ban: Ban user from groupchat');
|
||||||
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin');
|
expect(info_messages.pop().textContent).toBe('/admin: Change user\'s affiliation to admin');
|
||||||
|
expect(info_messages.pop().textContent).toBe('You can run the following commands');
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -41,6 +41,10 @@ import xss from "xss";
|
|||||||
const { Backbone, Promise, Strophe, moment, f, sizzle, _, $build, $iq, $msg, $pres } = converse.env;
|
const { Backbone, Promise, Strophe, moment, f, sizzle, _, $build, $iq, $msg, $pres } = converse.env;
|
||||||
const u = converse.env.utils;
|
const u = converse.env.utils;
|
||||||
const AFFILIATION_CHANGE_COMANDS = ['admin', 'ban', 'owner', 'member', 'revoke'];
|
const AFFILIATION_CHANGE_COMANDS = ['admin', 'ban', 'owner', 'member', 'revoke'];
|
||||||
|
const OWNER_COMMANDS = ['owner'];
|
||||||
|
const ADMIN_COMMANDS = ['admin', 'ban', 'deop', 'destroy', 'member', 'op', 'revoke'];
|
||||||
|
const MODERATOR_COMMANDS = ['kick', 'mute', 'voice'];
|
||||||
|
const VISITOR_COMMANDS = ['nick'];
|
||||||
|
|
||||||
converse.plugins.add('converse-muc-views', {
|
converse.plugins.add('converse-muc-views', {
|
||||||
/* Dependencies are other plugins which might be
|
/* Dependencies are other plugins which might be
|
||||||
@ -882,19 +886,27 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
||||||
},
|
},
|
||||||
|
|
||||||
verifyRoles (roles) {
|
verifyRoles (roles, occupant, show_error=true) {
|
||||||
const me = this.model.occupants.findWhere({'jid': _converse.bare_jid});
|
if (!occupant) {
|
||||||
if (!_.includes(roles, me.get('role'))) {
|
occupant = this.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||||
|
}
|
||||||
|
if (!_.includes(roles, occupant.get('role'))) {
|
||||||
|
if (show_error) {
|
||||||
this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'))
|
this.showErrorMessage(__('Forbidden: you do not have the necessary role in order to do that.'))
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
verifyAffiliations (affiliations) {
|
verifyAffiliations (affiliations, occupant, show_error=true) {
|
||||||
const me = this.model.occupants.findWhere({'jid': _converse.bare_jid});
|
if (!occupant) {
|
||||||
if (!_.includes(affiliations, me.get('affiliation'))) {
|
occupant = this.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||||
|
}
|
||||||
|
if (!_.includes(affiliations, occupant.get('affiliation'))) {
|
||||||
|
if (show_error) {
|
||||||
this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'))
|
this.showErrorMessage(__('Forbidden: you do not have the necessary affiliation in order to do that.'))
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -938,7 +950,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'admin':
|
case 'admin': {
|
||||||
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -950,8 +962,9 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
(err) => this.onCommandError(err)
|
(err) => this.onCommandError(err)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'ban':
|
}
|
||||||
if (!this.verifyAffiliations(['owner', 'admin']) || !this.validateRoleChangeCommand(command, args)) {
|
case 'ban': {
|
||||||
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.model.setAffiliation('outcast', [{
|
this.model.setAffiliation('outcast', [{
|
||||||
@ -962,7 +975,14 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
(err) => this.onCommandError(err)
|
(err) => this.onCommandError(err)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'deop':
|
}
|
||||||
|
case 'deop': {
|
||||||
|
// FIXME: /deop only applies to setting a moderators
|
||||||
|
// role to "participant" (which only admin/owner can
|
||||||
|
// do). Moderators can however set non-moderator's role
|
||||||
|
// to participant (e.g. visitor => participant).
|
||||||
|
// Currently we don't distinguish between these two
|
||||||
|
// cases.
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -970,7 +990,8 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.get('jid'), args[0], 'participant', args[1],
|
this.model.get('jid'), args[0], 'participant', args[1],
|
||||||
undefined, this.onCommandError.bind(this));
|
undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
case 'destroy':
|
}
|
||||||
|
case 'destroy': {
|
||||||
if (!this.verifyAffiliations(['owner'])) {
|
if (!this.verifyAffiliations(['owner'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -978,11 +999,29 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
.then(() => this.close())
|
.then(() => this.close())
|
||||||
.catch(e => this.onCommandError(e));
|
.catch(e => this.onCommandError(e));
|
||||||
break;
|
break;
|
||||||
case 'help':
|
}
|
||||||
this.showHelpMessages(_.filter([
|
case 'help': {
|
||||||
|
// FIXME: The availability of some of these commands
|
||||||
|
// depend on the MUCs configuration (e.g. whether it's
|
||||||
|
// moderated or not). We need to take that into
|
||||||
|
// consideration.
|
||||||
|
let allowed_commands = ['clear', 'help', 'me', 'nick', 'subject', 'topic', 'register'];
|
||||||
|
const occupant = this.model.occupants.findWhere({'jid': _converse.bare_jid});
|
||||||
|
if (this.verifyAffiliations('owner', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(OWNER_COMMANDS).concat(ADMIN_COMMANDS);
|
||||||
|
} else if (this.verifyAffiliations('admin', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(ADMIN_COMMANDS);
|
||||||
|
}
|
||||||
|
if (this.verifyRoles('moderator', occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(MODERATOR_COMMANDS).concat(VISITOR_COMMANDS);
|
||||||
|
} else if (!this.verifyRoles(['visitor', 'participant', 'moderator'], occupant, false)) {
|
||||||
|
allowed_commands = allowed_commands.concat(VISITOR_COMMANDS);
|
||||||
|
}
|
||||||
|
this.showHelpMessages([`<strong>${__("You can run the following commands")}</strong>`]);
|
||||||
|
this.showHelpMessages([
|
||||||
`<strong>/admin</strong>: ${__("Change user's affiliation to admin")}`,
|
`<strong>/admin</strong>: ${__("Change user's affiliation to admin")}`,
|
||||||
`<strong>/ban</strong>: ${__('Ban user from groupchat')}`,
|
`<strong>/ban</strong>: ${__('Ban user from groupchat')}`,
|
||||||
`<strong>/clear</strong>: ${__('Remove messages')}`,
|
`<strong>/clear</strong>: ${__('Clear the chat area')}`,
|
||||||
`<strong>/deop</strong>: ${__('Change user role to participant')}`,
|
`<strong>/deop</strong>: ${__('Change user role to participant')}`,
|
||||||
`<strong>/destroy</strong>: ${__('Remove this groupchat')}`,
|
`<strong>/destroy</strong>: ${__('Remove this groupchat')}`,
|
||||||
`<strong>/help</strong>: ${__('Show this menu')}`,
|
`<strong>/help</strong>: ${__('Show this menu')}`,
|
||||||
@ -993,15 +1032,16 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
`<strong>/nick</strong>: ${__('Change your nickname')}`,
|
`<strong>/nick</strong>: ${__('Change your nickname')}`,
|
||||||
`<strong>/op</strong>: ${__('Grant moderator role to user')}`,
|
`<strong>/op</strong>: ${__('Grant moderator role to user')}`,
|
||||||
`<strong>/owner</strong>: ${__('Grant ownership of this groupchat')}`,
|
`<strong>/owner</strong>: ${__('Grant ownership of this groupchat')}`,
|
||||||
`<strong>/register</strong>: ${__("Register a nickname for this groupchat")}`,
|
`<strong>/register</strong>: ${__("Register your nickname")}`,
|
||||||
`<strong>/revoke</strong>: ${__("Revoke user's membership")}`,
|
`<strong>/revoke</strong>: ${__("Revoke user's membership")}`,
|
||||||
`<strong>/subject</strong>: ${__('Set groupchat subject')}`,
|
`<strong>/subject</strong>: ${__('Set groupchat subject')}`,
|
||||||
`<strong>/topic</strong>: ${__('Set groupchat subject (alias for /subject)')}`,
|
`<strong>/topic</strong>: ${__('Set groupchat subject (alias for /subject)')}`,
|
||||||
`<strong>/voice</strong>: ${__('Allow muted user to post messages')}`
|
`<strong>/voice</strong>: ${__('Allow muted user to post messages')}`
|
||||||
], line => (_.every(disabled_commands, element => (!line.startsWith(element+'<', 9))))
|
].filter(line => disabled_commands.every(c => (!line.startsWith(c+'<', 9))))
|
||||||
));
|
.filter(line => allowed_commands.some(c => line.startsWith(c+'<', 9)))
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'kick':
|
} case 'kick': {
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1009,7 +1049,8 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.get('jid'), args[0], 'none', args[1],
|
this.model.get('jid'), args[0], 'none', args[1],
|
||||||
undefined, this.onCommandError.bind(this));
|
undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
case 'mute':
|
}
|
||||||
|
case 'mute': {
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1017,6 +1058,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.get('jid'), args[0], 'visitor', args[1],
|
this.model.get('jid'), args[0], 'visitor', args[1],
|
||||||
undefined, this.onCommandError.bind(this));
|
undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'member': {
|
case 'member': {
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
@ -1034,7 +1076,8 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
.then(() => this.model.occupants.fetchMembers())
|
.then(() => this.model.occupants.fetchMembers())
|
||||||
.catch(err => this.onCommandError(err));
|
.catch(err => this.onCommandError(err));
|
||||||
break;
|
break;
|
||||||
} case 'nick':
|
}
|
||||||
|
case 'nick': {
|
||||||
if (!this.verifyRoles(['visitor', 'participant', 'moderator'])) {
|
if (!this.verifyRoles(['visitor', 'participant', 'moderator'])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1044,6 +1087,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
id: _converse.connection.getUniqueId()
|
id: _converse.connection.getUniqueId()
|
||||||
}).tree());
|
}).tree());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'owner':
|
case 'owner':
|
||||||
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
@ -1056,7 +1100,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
(err) => this.onCommandError(err)
|
(err) => this.onCommandError(err)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'op':
|
case 'op': {
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1064,7 +1108,8 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.get('jid'), args[0], 'moderator', args[1],
|
this.model.get('jid'), args[0], 'moderator', args[1],
|
||||||
undefined, this.onCommandError.bind(this));
|
undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
case 'register':
|
}
|
||||||
|
case 'register': {
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
this.showErrorMessage(__('Error: invalid number of arguments'))
|
this.showErrorMessage(__('Error: invalid number of arguments'))
|
||||||
} else {
|
} else {
|
||||||
@ -1073,7 +1118,8 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'revoke':
|
}
|
||||||
|
case 'revoke': {
|
||||||
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyAffiliations(['admin', 'owner']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1085,6 +1131,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
(err) => this.onCommandError(err)
|
(err) => this.onCommandError(err)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'topic':
|
case 'topic':
|
||||||
case 'subject':
|
case 'subject':
|
||||||
// TODO: should be done via API call to _converse.api.rooms
|
// TODO: should be done via API call to _converse.api.rooms
|
||||||
@ -1096,7 +1143,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
}).c("subject", {xmlns: "jabber:client"}).t(match[2] || "").tree()
|
}).c("subject", {xmlns: "jabber:client"}).t(match[2] || "").tree()
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'voice':
|
case 'voice': {
|
||||||
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
if (!this.verifyRoles(['moderator']) || !this.validateRoleChangeCommand(command, args)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1104,6 +1151,7 @@ converse.plugins.add('converse-muc-views', {
|
|||||||
this.model.get('jid'), args[0], 'participant', args[1],
|
this.model.get('jid'), args[0], 'participant', args[1],
|
||||||
undefined, this.onCommandError.bind(this));
|
undefined, this.onCommandError.bind(this));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
|
return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user