import log from '@converse/headless/log'; import tpl_moderator_tools from './templates/moderator-tools.js'; import { AFFILIATIONS, ROLES } from '@converse/headless/plugins/muc/index.js'; import { CustomElement } from 'shared/components/element.js'; import { __ } from 'i18n'; import { _converse, api, converse } from '@converse/headless/core'; import { getAssignableRoles } from '@converse/headless/plugins/muc/utils.js'; import { getAffiliationList, getAssignableAffiliations, setAffiliation, } from '@converse/headless/plugins/muc/affiliations/utils.js'; const { Strophe, sizzle, u } = converse.env; export default class ModeratorTools extends CustomElement { static get properties () { return { affiliations_filter: { type: String, attribute: false }, alert_message: { type: String, attribute: false }, alert_type: { type: String, attribute: false }, model: { type: Object }, muc: { type: Object }, roles_filter: { type: String, attribute: false }, users_with_affiliation: { type: Array, attribute: false }, users_with_role: { type: Array, attribute: false }, }; } constructor () { super(); this.affiliations_filter = ''; this.roles_filter = ''; } connectedCallback () { super.connectedCallback(); this.initialize(); } initialize () { this.listenTo(this.model, 'change:role', this.onSearchRoleChange, this); this.listenTo(this.model, 'change:affiliation', this.onSearchAffiliationChange, this); } render () { const occupant = this.muc.occupants.findWhere({ 'jid': _converse.bare_jid }); return tpl_moderator_tools( Object.assign(this.model.toJSON(), { '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), 'filterAffiliationResults': ev => this.filterAffiliationResults(ev), 'filterRoleResults': ev => this.filterRoleResults(ev), '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_roles': ROLES.filter(a => !api.settings.get('modtools_disable_query').includes(a)), 'roles_filter': this.roles_filter, 'switchTab': ev => this.switchTab(ev), 'toggleForm': ev => this.toggleForm(ev), 'users_with_affiliation': this.users_with_affiliation, 'users_with_role': this.users_with_role, }) ); } async onSearchAffiliationChange () { this.clearAlert(); this.loading_users_with_affiliation = true; this.users_with_affiliation = null; const affiliation = this.model.get('affiliation'); if (this.shouldFetchAffiliationsList()) { const muc_jid = this.muc.get('jid'); const result = await getAffiliationList(affiliation, muc_jid); if (result instanceof Error) { this.alert(result.message, 'danger'); this.users_with_affiliation = []; } else { this.users_with_affiliation = result; } } else { this.users_with_affiliation = this.muc.getOccupantsWithAffiliation(affiliation); } this.loading_users_with_affiliation = false; } onSearchRoleChange () { this.clearAlert(); this.users_with_role = this.muc.getOccupantsWithRole(this.model.get('role')); } shouldFetchAffiliationsList () { const affiliation = this.model.get('affiliation'); if (affiliation === 'none') { return false; } const chatroom = this.muc; const auto_fetched_affs = chatroom.occupants.getAutoFetchedAffiliationLists(); if (auto_fetched_affs.includes(affiliation)) { return false; } else { return true; } } toggleForm (ev) { // eslint-disable-line class-methods-use-this ev.stopPropagation(); ev.preventDefault(); const form_class = ev.target.getAttribute('data-form'); const form = u.ancestor(ev.target, '.list-group-item').querySelector(`.${form_class}`); if (u.hasClass('hidden', form)) { u.removeClass('hidden', form); } else { u.addClass('hidden', form); } } filterRoleResults (ev) { this.roles_filter = ev.target.value; this.render(); } filterAffiliationResults (ev) { this.affiliations_filter = ev.target.value; } queryRole (ev) { ev.stopPropagation(); ev.preventDefault(); const data = new FormData(ev.target); const role = data.get('role'); this.model.set({ 'role': null }, { 'silent': true }); this.model.set({ 'role': role }); } queryAffiliation (ev) { ev.stopPropagation(); ev.preventDefault(); const data = new FormData(ev.target); const affiliation = data.get('affiliation'); this.model.set({ 'affiliation': null }, { 'silent': true }); this.model.set({ 'affiliation': affiliation }); } alert (message, type) { this.alert_message = message; this.alert_type = type; } clearAlert () { this.alert_message = undefined; 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.model.get('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.model.set({ 'affiliation': null }, { 'silent': true }); this.model.set({ 'affiliation': current_affiliation }); this.alert(__('Affiliation changed'), 'primary'); } assignRole (ev) { ev.stopPropagation(); ev.preventDefault(); this.clearAlert(); const data = new FormData(ev.target); const occupant = this.muc.getOccupant(data.get('jid') || data.get('nick')); const role = data.get('role'); const reason = data.get('reason'); const current_role = this.model.get('role'); this.muc.setRole( occupant, role, reason, () => { this.alert(__('Role changed'), 'primary'); this.model.set({ 'role': null }, { 'silent': true }); this.model.set({ 'role': current_role }); }, e => { if (sizzle(`not-allowed[xmlns="${Strophe.NS.STANZAS}"]`, e).length) { this.alert(__("You're not allowed to make that change"), 'danger'); } else { this.alert(__('Sorry, something went wrong while trying to set the role'), 'danger'); if (u.isErrorObject(e)) { log.error(e); } } } ); } } api.elements.define('converse-modtools', ModeratorTools);