Turn the MUC affiliation form into a component
So that it can be used elsewhere, for example in the occupant modal.
This commit is contained in:
parent
6ce8879e9c
commit
57f489f61b
|
@ -45,7 +45,7 @@ export async function getAffiliationList (affiliation, muc_jid) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Given an occupant model, see which affiliations may be assigned to that user.
|
||||
* Given an occupant model, see which affiliations may be assigned by that user
|
||||
* @param { Model } occupant
|
||||
* @returns { Array<('owner'|'admin'|'member'|'outcast'|'none')> } - An array of assignable affiliations
|
||||
*/
|
||||
|
@ -54,9 +54,9 @@ export function getAssignableAffiliations (occupant) {
|
|||
if (!Array.isArray(disabled)) {
|
||||
disabled = disabled ? AFFILIATIONS : [];
|
||||
}
|
||||
if (occupant.get('affiliation') === 'owner') {
|
||||
if (occupant?.get('affiliation') === 'owner') {
|
||||
return AFFILIATIONS.filter(a => !disabled.includes(a));
|
||||
} else if (occupant.get('affiliation') === 'admin') {
|
||||
} else if (occupant?.get('affiliation') === 'admin') {
|
||||
return AFFILIATIONS.filter(a => !['owner', 'admin', ...disabled].includes(a));
|
||||
} else {
|
||||
return [];
|
||||
|
|
69
src/plugins/muc-views/affiliation-form.js
Normal file
69
src/plugins/muc-views/affiliation-form.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import log from '@converse/headless/log';
|
||||
import tplAffiliationForm from './templates/affiliation-form.js';
|
||||
import { CustomElement } from 'shared/components/element';
|
||||
import { __ } from 'i18n';
|
||||
import { api, converse } from '@converse/headless/core';
|
||||
import { setAffiliation } from '@converse/headless/plugins/muc/affiliations/utils.js';
|
||||
|
||||
const { Strophe, sizzle } = converse.env;
|
||||
|
||||
class AffiliationForm extends CustomElement {
|
||||
static get properties () {
|
||||
return {
|
||||
muc: { type: Object },
|
||||
jid: { type: String },
|
||||
affiliation: { type: String },
|
||||
alert_message: { type: String, attribute: false },
|
||||
alert_type: { type: String, attribute: false },
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
return tplAffiliationForm(this);
|
||||
}
|
||||
|
||||
alert (message, type) {
|
||||
this.alert_message = message;
|
||||
this.alert_type = type;
|
||||
}
|
||||
|
||||
async assignAffiliation (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.alert(); // clear alert messages
|
||||
|
||||
const data = new FormData(ev.target);
|
||||
const affiliation = data.get('affiliation');
|
||||
const attrs = {
|
||||
jid: this.jid,
|
||||
reason: data.get('reason'),
|
||||
};
|
||||
const muc_jid = this.muc.get('jid');
|
||||
try {
|
||||
await setAffiliation(affiliation, muc_jid, [attrs]);
|
||||
} catch (e) {
|
||||
if (e === null) {
|
||||
this.alert(__('Timeout error while trying to set the affiliation'), 'danger');
|
||||
} else if (sizzle(`not-allowed[xmlns="${Strophe.NS.STANZAS}"]`, e).length) {
|
||||
this.alert(__("Sorry, you're not allowed to make that change"), 'danger');
|
||||
} else {
|
||||
this.alert(__('Sorry, something went wrong while trying to set the affiliation'), 'danger');
|
||||
}
|
||||
log.error(e);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.muc.occupants.fetchMembers();
|
||||
|
||||
/**
|
||||
* @event affiliationChanged
|
||||
* @example
|
||||
* const el = document.querySelector('converse-muc-affiliation-form');
|
||||
* el.addEventListener('affiliationChanged', () => { ... });
|
||||
*/
|
||||
const event = new CustomEvent('affiliationChanged', { bubbles: true });
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
api.elements.define('converse-muc-affiliation-form', AffiliationForm);
|
|
@ -4,6 +4,7 @@
|
|||
* @license Mozilla Public License (MPLv2)
|
||||
*/
|
||||
import '../chatboxviews/index.js';
|
||||
import './affiliation-form.js';
|
||||
import MUCView from './muc.js';
|
||||
import { api, converse } from '@converse/headless/core.js';
|
||||
import { clearHistory, parseMessageForMUCCommands } from './utils.js';
|
||||
|
|
|
@ -3,14 +3,10 @@ import tplModeratorTools from './templates/moderator-tools.js';
|
|||
import { AFFILIATIONS, ROLES } from '@converse/headless/plugins/muc/constants.js';
|
||||
import { CustomElement } from 'shared/components/element.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core.js';
|
||||
import { api, converse } from '@converse/headless/core.js';
|
||||
import { getAffiliationList, getAssignableAffiliations } from '@converse/headless/plugins/muc/affiliations/utils.js';
|
||||
import { getAssignableRoles, getAutoFetchedAffiliationLists } from '@converse/headless/plugins/muc/utils.js';
|
||||
import { getOpenPromise } from '@converse/openpromise';
|
||||
import {
|
||||
getAffiliationList,
|
||||
getAssignableAffiliations,
|
||||
setAffiliation,
|
||||
} from '@converse/headless/plugins/muc/affiliations/utils.js';
|
||||
|
||||
import './styles/moderator-tools.scss';
|
||||
|
||||
|
@ -40,6 +36,12 @@ export default class ModeratorTools extends CustomElement {
|
|||
this.affiliations_filter = '';
|
||||
this.role = '';
|
||||
this.roles_filter = '';
|
||||
|
||||
this.addEventListener("affiliationChanged", () => {
|
||||
this.alert(__('Affiliation changed'), 'primary');
|
||||
this.onSearchAffiliationChange();
|
||||
this.requestUpdate()
|
||||
});
|
||||
}
|
||||
|
||||
updated (changed) {
|
||||
|
@ -58,12 +60,11 @@ export default class ModeratorTools extends CustomElement {
|
|||
|
||||
render () {
|
||||
if (this.muc?.occupants) {
|
||||
const occupant = this.muc.occupants.findWhere({ 'jid': _converse.bare_jid });
|
||||
return tplModeratorTools({
|
||||
const occupant = this.muc.occupants.getOwnOccupant();
|
||||
return tplModeratorTools(this, {
|
||||
'affiliations_filter': this.affiliations_filter,
|
||||
'alert_message': this.alert_message,
|
||||
'alert_type': this.alert_type,
|
||||
'assignAffiliation': ev => this.assignAffiliation(ev),
|
||||
'assignRole': ev => this.assignRole(ev),
|
||||
'assignable_affiliations': getAssignableAffiliations(occupant),
|
||||
'assignable_roles': getAssignableRoles(occupant),
|
||||
|
@ -72,7 +73,9 @@ export default class ModeratorTools extends CustomElement {
|
|||
'loading_users_with_affiliation': this.loading_users_with_affiliation,
|
||||
'queryAffiliation': ev => this.queryAffiliation(ev),
|
||||
'queryRole': ev => this.queryRole(ev),
|
||||
'queryable_affiliations': AFFILIATIONS.filter(a => !api.settings.get('modtools_disable_query').includes(a)),
|
||||
'queryable_affiliations': AFFILIATIONS.filter(
|
||||
a => !api.settings.get('modtools_disable_query').includes(a)
|
||||
),
|
||||
'queryable_roles': ROLES.filter(a => !api.settings.get('modtools_disable_query').includes(a)),
|
||||
'roles_filter': this.roles_filter,
|
||||
'switchTab': ev => this.switchTab(ev),
|
||||
|
@ -80,7 +83,7 @@ export default class ModeratorTools extends CustomElement {
|
|||
'toggleForm': ev => this.toggleForm(ev),
|
||||
'users_with_affiliation': this.users_with_affiliation,
|
||||
'users_with_role': this.users_with_role,
|
||||
})
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
@ -94,9 +97,8 @@ export default class ModeratorTools extends CustomElement {
|
|||
}
|
||||
|
||||
async onSearchAffiliationChange () {
|
||||
if (!this.affiliation) {
|
||||
return;
|
||||
}
|
||||
if (!this.affiliation) return;
|
||||
|
||||
await this.initialized;
|
||||
this.clearAlert();
|
||||
this.loading_users_with_affiliation = true;
|
||||
|
@ -138,12 +140,13 @@ export default class ModeratorTools extends CustomElement {
|
|||
}
|
||||
}
|
||||
|
||||
toggleForm (ev) { // eslint-disable-line class-methods-use-this
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
toggleForm (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const toggle = u.ancestor(ev.target, '.toggle-form');
|
||||
const form_class = toggle.getAttribute('data-form');
|
||||
const form = u.ancestor(toggle, '.list-group-item').querySelector(`.${form_class}`);
|
||||
const sel = toggle.getAttribute('data-form');
|
||||
const form = u.ancestor(toggle, '.list-group-item').querySelector(sel);
|
||||
if (u.hasClass('hidden', form)) {
|
||||
u.removeClass('hidden', form);
|
||||
} else {
|
||||
|
@ -188,37 +191,6 @@ export default class ModeratorTools extends CustomElement {
|
|||
this.alert_type = undefined;
|
||||
}
|
||||
|
||||
async assignAffiliation (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.clearAlert();
|
||||
const data = new FormData(ev.target);
|
||||
const affiliation = data.get('affiliation');
|
||||
const attrs = {
|
||||
'jid': data.get('jid'),
|
||||
'reason': data.get('reason'),
|
||||
};
|
||||
const current_affiliation = this.affiliation;
|
||||
const muc_jid = this.muc.get('jid');
|
||||
try {
|
||||
await setAffiliation(affiliation, muc_jid, [attrs]);
|
||||
} catch (e) {
|
||||
if (e === null) {
|
||||
this.alert(__('Timeout error while trying to set the affiliation'), 'danger');
|
||||
} else if (sizzle(`not-allowed[xmlns="${Strophe.NS.STANZAS}"]`, e).length) {
|
||||
this.alert(__("Sorry, you're not allowed to make that change"), 'danger');
|
||||
} else {
|
||||
this.alert(__('Sorry, something went wrong while trying to set the affiliation'), 'danger');
|
||||
}
|
||||
log.error(e);
|
||||
return;
|
||||
}
|
||||
await this.muc.occupants.fetchMembers();
|
||||
this.affiliation = null;
|
||||
this.affiliation = current_affiliation;
|
||||
this.alert(__('Affiliation changed'), 'primary');
|
||||
}
|
||||
|
||||
assignRole (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
|
36
src/plugins/muc-views/templates/affiliation-form.js
Normal file
36
src/plugins/muc-views/templates/affiliation-form.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { __ } from 'i18n';
|
||||
import { html } from "lit";
|
||||
import { getAssignableAffiliations } from '@converse/headless/plugins/muc/affiliations/utils.js';
|
||||
|
||||
export default (el) => {
|
||||
const i18n_change_affiliation = __('Change affiliation');
|
||||
const i18n_new_affiliation = __('New affiliation');
|
||||
const i18n_reason = __('Reason');
|
||||
const occupant = el.muc.getOwnOccupant();
|
||||
const assignable_affiliations = getAssignableAffiliations(occupant);
|
||||
|
||||
return html`
|
||||
<form class="affiliation-form" @submit=${ev => el.assignAffiliation(ev)}>
|
||||
${el.alert_message ? html`<div class="alert alert-${el.alert_type}" role="alert">${el.alert_message}</div>` : '' }
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label><strong>${i18n_new_affiliation}:</strong></label>
|
||||
<select class="custom-select select-affiliation" name="affiliation">
|
||||
${ assignable_affiliations.map(aff => html`<option value="${aff}" ?selected=${aff === el.affiliation}>${aff}</option>`) }
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><strong>${i18n_reason}:</strong></label>
|
||||
<input class="form-control" type="text" name="reason"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col">
|
||||
<input type="submit" class="btn btn-primary" name="change" value="${i18n_change_affiliation}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
}
|
|
@ -94,45 +94,13 @@ const role_list_item = (o) => html`
|
|||
`;
|
||||
|
||||
|
||||
const tplSetAffiliationForm = (o) => {
|
||||
const i18n_change_affiliation = __('Change affiliation');
|
||||
const i18n_new_affiliation = __('New affiliation');
|
||||
const i18n_reason = __('Reason');
|
||||
return html`
|
||||
<form class="affiliation-form hidden" @submit=${o.assignAffiliation}>
|
||||
<div class="form-group">
|
||||
<input type="hidden" name="jid" value="${o.item.jid}"/>
|
||||
<input type="hidden" name="nick" value="${o.item.nick}"/>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label><strong>${i18n_new_affiliation}:</strong></label>
|
||||
<select class="custom-select select-affiliation" name="affiliation">
|
||||
${ o.assignable_affiliations.map(aff => html`<option value="${aff}" ?selected=${aff === o.item.affiliation}>${aff}</option>`) }
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><strong>${i18n_reason}:</strong></label>
|
||||
<input class="form-control" type="text" name="reason"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col">
|
||||
<input type="submit" class="btn btn-primary" name="change" value="${i18n_change_affiliation}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
const affiliation_form_toggle = (o) => html`
|
||||
<a href="#" data-form="affiliation-form" class="toggle-form right" color="var(--subdued-color)" @click=${o.toggleForm}>
|
||||
<a href="#" data-form="converse-muc-affiliation-form" class="toggle-form right" color="var(--subdued-color)" @click=${o.toggleForm}>
|
||||
<converse-icon class="fa fa-wrench" size="1em"></converse-icon>
|
||||
</a>`;
|
||||
|
||||
|
||||
const affiliation_list_item = (o) => html`
|
||||
const affiliation_list_item = (el, o) => html`
|
||||
<li class="list-group-item" data-nick="${o.item.nick}">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item active">
|
||||
|
@ -143,7 +111,9 @@ const affiliation_list_item = (o) => html`
|
|||
</li>
|
||||
<li class="list-group-item">
|
||||
<div><strong>Affiliation:</strong> ${o.item.affiliation} ${o.assignable_affiliations.length ? affiliation_form_toggle(o) : ''}</div>
|
||||
${o.assignable_affiliations.length ? tplSetAffiliationForm(o) : ''}
|
||||
${o.assignable_affiliations.length ?
|
||||
html`<converse-muc-affiliation-form class="hidden" .muc=${el.muc} jid=${o.item.jid} affiliation=${o.item.affiliation}></converse-muc-affiliation-form>` : ''
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -174,7 +144,7 @@ const tplNavigation = (o) => html`
|
|||
`;
|
||||
|
||||
|
||||
export default (o) => {
|
||||
export default (el, o) => {
|
||||
const i18n_affiliation = __('Affiliation');
|
||||
const i18n_no_users_with_aff = __('No users with that affiliation found.')
|
||||
const i18n_no_users_with_role = __('No users with that role found.');
|
||||
|
@ -235,7 +205,7 @@ export default (o) => {
|
|||
|
||||
${ (o.users_with_affiliation instanceof Error) ?
|
||||
html`<li class="list-group-item">${o.users_with_affiliation.message}</li>` :
|
||||
(o.users_with_affiliation || []).map(item => ((item.nick || item.jid).match(new RegExp(o.affiliations_filter, 'i')) ? affiliation_list_item(Object.assign({item}, o)) : '')) }
|
||||
(o.users_with_affiliation || []).map(item => ((item.nick || item.jid).match(new RegExp(o.affiliations_filter, 'i')) ? affiliation_list_item(el, Object.assign({item}, o)) : '')) }
|
||||
</ul>
|
||||
</div>
|
||||
</div>` : '' }
|
||||
|
|
|
@ -37,7 +37,7 @@ describe("The groupchat moderator tool", function () {
|
|||
await u.waitUntil(() => (view.model.occupants.length === 5), 1000);
|
||||
|
||||
const modal = await openModtools(_converse, view);
|
||||
let tab = modal.querySelector('#affiliations-tab');
|
||||
const tab = modal.querySelector('#affiliations-tab');
|
||||
// Clear so that we don't match older stanzas
|
||||
_converse.connection.IQ_stanzas = [];
|
||||
tab.click();
|
||||
|
@ -70,10 +70,12 @@ describe("The groupchat moderator tool", function () {
|
|||
expect(user_els[1].querySelector('.list-group-item:nth-child(3n) div').textContent.trim()).toBe('Affiliation: owner');
|
||||
|
||||
const toggle = user_els[1].querySelector('.list-group-item:nth-child(3n) .toggle-form');
|
||||
const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
||||
expect(u.hasClass('hidden', form)).toBeTruthy();
|
||||
const component = user_els[1].querySelector('.list-group-item:nth-child(3n) converse-muc-affiliation-form');
|
||||
expect(u.hasClass('hidden', component)).toBeTruthy();
|
||||
toggle.click();
|
||||
expect(u.hasClass('hidden', form)).toBeFalsy();
|
||||
expect(u.hasClass('hidden', component)).toBeFalsy();
|
||||
|
||||
const form = user_els[1].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
||||
select = form.querySelector('.select-affiliation');
|
||||
expect(select.value).toBe('owner');
|
||||
select.value = 'admin';
|
||||
|
@ -372,10 +374,12 @@ describe("The groupchat moderator tool", function () {
|
|||
|
||||
const user_els = modal.querySelectorAll('.list-group--users > li');
|
||||
const toggle = user_els[0].querySelector('.list-group-item:nth-child(3n) .toggle-form');
|
||||
const form = user_els[0].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
||||
expect(u.hasClass('hidden', form)).toBeTruthy();
|
||||
const component = user_els[0].querySelector('.list-group-item:nth-child(3n) converse-muc-affiliation-form');
|
||||
expect(u.hasClass('hidden', component)).toBeTruthy();
|
||||
toggle.click();
|
||||
expect(u.hasClass('hidden', form)).toBeFalsy();
|
||||
expect(u.hasClass('hidden', component)).toBeFalsy();
|
||||
|
||||
const form = user_els[0].querySelector('.list-group-item:nth-child(3n) .affiliation-form');
|
||||
const change_affiliation_dropdown = form.querySelector('.select-affiliation');
|
||||
expect(change_affiliation_dropdown.value).toBe('member');
|
||||
change_affiliation_dropdown.value = 'admin';
|
||||
|
|
Loading…
Reference in New Issue
Block a user