diff --git a/src/components/ConversationSettings/BanSettings/BannedItem.vue b/src/components/ConversationSettings/BanSettings/BannedItem.vue index cddd48399db..2ffde1a5171 100644 --- a/src/components/ConversationSettings/BanSettings/BannedItem.vue +++ b/src/components/ConversationSettings/BanSettings/BannedItem.vue @@ -6,7 +6,7 @@ @@ -54,12 +56,12 @@ export default { computed: { banInfo() { return [ - t('spreed', 'Banned by: {actor}', { actor: this.ban.actorId }, - undefined, { escape: false, sanitize: false }), - t('spreed', 'Date: {date}', { date: moment(this.ban.bannedTime * 1000).format('lll') }, - undefined, { escape: false, sanitize: false }), - t('spreed', 'Note: {note}', { note: this.ban.internalNote }, - undefined, { escape: false, sanitize: false }), + // TRANSLATORS name of a moderator who banned a participant + { label: t('spreed', 'Banned by:'), value: this.ban.moderatorDisplayName }, + // TRANSLATORS Date and time of ban creation + { label: t('spreed', 'Date:'), value: moment(this.ban.bannedTime * 1000).format('lll') }, + // TRANSLATORS Internal note for moderators, usually a reason for this ban + { label: t('spreed', 'Note:'), value: this.ban.internalNote }, ] }, }, diff --git a/src/components/RightSidebar/Participants/Participant.spec.js b/src/components/RightSidebar/Participants/Participant.spec.js index b69bad0e19f..bd2689f1621 100644 --- a/src/components/RightSidebar/Participants/Participant.spec.js +++ b/src/components/RightSidebar/Participants/Participant.spec.js @@ -17,7 +17,7 @@ import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js' -import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' +import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js' import Participant from './Participant.vue' import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue' @@ -113,7 +113,7 @@ describe('Participant.vue', () => { NcCheckboxRadioSwitch, NcDialog, NcInputField, - NcTextField, + NcTextArea, }, directives: { tooltip: tooltipMock, @@ -676,10 +676,10 @@ describe('Participant.vue', () => { const checkbox = dialog.findComponent(NcCheckboxRadioSwitch) await checkbox.find('input').trigger('change') - const input = dialog.findComponent(NcTextField) - expect(input.exists()).toBeTruthy() - input.find('input').setValue(internalNote) - await input.find('input').trigger('change') + const textarea = dialog.findComponent(NcTextArea) + expect(textarea.exists()).toBeTruthy() + textarea.find('textarea').setValue(internalNote) + await textarea.find('textarea').trigger('change') const button = findNcButton(dialog, 'Remove') await button.find('button').trigger('click') @@ -766,12 +766,19 @@ describe('Participant.vue', () => { await testCannotRemove() }) - test('allows a moderator to ban a moderator', async () => { + test('allows a moderator to ban a user', async () => { conversation.participantType = PARTICIPANT.TYPE.MODERATOR participant.participantType = PARTICIPANT.TYPE.USER await testCanBan() }) + test('allows a moderator to ban a federated user', async () => { + conversation.participantType = PARTICIPANT.TYPE.MODERATOR + participant.actorType = ATTENDEE.ACTOR_TYPE.FEDERATED_USERS + participant.participantType = PARTICIPANT.TYPE.USER + await testCanBan() + }) + test('allows a moderator to ban a guest', async () => { conversation.participantType = PARTICIPANT.TYPE.MODERATOR participant.participantType = PARTICIPANT.TYPE.GUEST diff --git a/src/components/RightSidebar/Participants/Participant.vue b/src/components/RightSidebar/Participants/Participant.vue index 921258c3c02..835874cd1e3 100644 --- a/src/components/RightSidebar/Participants/Participant.vue +++ b/src/components/RightSidebar/Participants/Participant.vue @@ -318,17 +318,20 @@ {{ t('spreed', 'Also ban from this conversation') }} @@ -376,7 +379,7 @@ import NcActionText from '@nextcloud/vue/dist/Components/NcActionText.js' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js' -import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js' +import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js' import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js' import ParticipantPermissionsEditor from './ParticipantPermissionsEditor.vue' @@ -411,7 +414,7 @@ export default { NcButton, NcCheckboxRadioSwitch, NcDialog, - NcTextField, + NcTextArea, ParticipantPermissionsEditor, // Icons Account, @@ -488,6 +491,7 @@ export default { isBanParticipant: false, internalNote: '', disabled: false, + isLoading: false, } }, @@ -796,10 +800,21 @@ export default { return this.canBeModerated && !this.isModerator && (this.participant.actorType === ATTENDEE.ACTOR_TYPE.USERS + || this.participant.actorType === ATTENDEE.ACTOR_TYPE.FEDERATED_USERS || this.participant.actorType === ATTENDEE.ACTOR_TYPE.GUESTS || this.participant.actorType === ATTENDEE.ACTOR_TYPE.EMAILS) }, + maxLengthWarning() { + if (this.internalNote.length <= 4000) { + return '' + } + return t('spreed', 'The text must be less than or equal to {maxLength} characters long. Your current text is {charactersCount} characters long.', { + maxLength: 4000, + charactersCount: this.internalNote.length, + }) + }, + removeParticipantLabel() { switch (this.participant.actorType) { case ATTENDEE.ACTOR_TYPE.GROUPS: @@ -995,15 +1010,22 @@ export default { }, async removeParticipant() { - await this.$store.dispatch('removeParticipant', { - token: this.token, - attendeeId: this.attendeeId, - banParticipant: this.isBanParticipant, - internalNote: this.internalNote, - }) - this.isBanParticipant = false - this.internalNote = '' - this.isRemoveDialogOpen = false + this.isLoading = true + try { + await this.$store.dispatch('removeParticipant', { + token: this.token, + attendeeId: this.attendeeId, + banParticipant: this.isBanParticipant, + internalNote: this.internalNote, + }) + this.isBanParticipant = false + this.internalNote = '' + this.isRemoveDialogOpen = false + } catch (error) { + console.error('Error while removing the participant: ', error) + } finally { + this.isLoading = false + } }, grantAllPermissions() { diff --git a/src/store/participantsStore.js b/src/store/participantsStore.js index 05da627ad1b..514d50573b4 100644 --- a/src/store/participantsStore.js +++ b/src/store/participantsStore.js @@ -581,7 +581,7 @@ const actions = { showSuccess(t('spreed', 'Participant is banned successfully')) } catch (error) { showError(t('spreed', 'Error while banning the participant')) - console.error('Error while banning the participant: ', error) + throw error } } await removeAttendeeFromConversation(token, attendeeId) diff --git a/src/views/ForbiddenView.vue b/src/views/ForbiddenView.vue index d44e077d291..69fbd099260 100644 --- a/src/views/ForbiddenView.vue +++ b/src/views/ForbiddenView.vue @@ -5,7 +5,7 @@