summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMaksim Sukharev <antreesy.web@gmail.com>2024-06-19 13:43:44 +0200
committerMaksim Sukharev <antreesy.web@gmail.com>2024-06-19 14:31:36 +0200
commitc3c27d75789fa211fbb8cd7d43c8ab210e25cb00 (patch)
tree7ea199872ac3237c9a00998b71b3b5d5f5610c54 /src
parentdb3a2edf9757d494b89e9e2a0231b7883ad6269c (diff)
feat(ban): list existing bans per conversation
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/components/ConversationSettings/BanSettings/BanSettings.vue132
-rw-r--r--src/components/ConversationSettings/BanSettings/BannedItem.vue101
-rw-r--r--src/components/ConversationSettings/ConversationSettingsDialog.vue7
3 files changed, 240 insertions, 0 deletions
diff --git a/src/components/ConversationSettings/BanSettings/BanSettings.vue b/src/components/ConversationSettings/BanSettings/BanSettings.vue
new file mode 100644
index 000000000..cc40d4487
--- /dev/null
+++ b/src/components/ConversationSettings/BanSettings/BanSettings.vue
@@ -0,0 +1,132 @@
+<!--
+ - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <div class="conversation-ban__settings">
+ <h4 class="app-settings-section__subtitle">
+ {{ t('spreed', 'Banned users') }}
+ </h4>
+ <div class="app-settings-section__hint">
+ {{ t('spreed', 'Manage the list of banned users in this conversation.') }}
+ </div>
+ <NcButton @click="modal = true">
+ {{ t('spreed', 'Manage bans') }}
+ </NcButton>
+
+ <NcModal v-if="modal"
+ container=".conversation-ban__settings"
+ @close="modal = false">
+ <div class="conversation-ban__content">
+ <h2 class="conversation-ban__title">
+ {{ t('spreed', 'Banned users') }}
+ </h2>
+
+ <ul v-if="banList.length" class="conversation-ban__list">
+ <BannedItem v-for="ban in banList"
+ :key="ban.id"
+ :ban="ban"
+ @unban-participant="handleUnban(ban.id)" />
+ </ul>
+
+ <NcEmptyContent v-else>
+ <template #icon>
+ <NcLoadingIcon v-if="isLoading" />
+ <AccountCancel v-else />
+ </template>
+
+ <template #description>
+ <p>{{ isLoading ? t('spreed', 'Loading …') : t('spreed', 'No banned users') }}</p>
+ </template>
+ </NcEmptyContent>
+ </div>
+ </NcModal>
+ </div>
+</template>
+
+<script>
+import AccountCancel from 'vue-material-design-icons/AccountCancel.vue'
+
+import { t } from '@nextcloud/l10n'
+
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
+import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
+import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
+import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
+
+import BannedItem from './BannedItem.vue'
+
+import { getConversationBans, unbanActor } from '../../../services/banService.ts'
+
+export default {
+ name: 'BanSettings',
+
+ components: {
+ NcButton,
+ NcEmptyContent,
+ NcLoadingIcon,
+ NcModal,
+ BannedItem,
+ // Icons
+ AccountCancel,
+ },
+
+ props: {
+ token: {
+ type: String,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ banList: [],
+ isLoading: true,
+ modal: false,
+ }
+ },
+
+ watch: {
+ modal(value) {
+ if (value) {
+ this.getList()
+ }
+ }
+ },
+
+ methods: {
+ t,
+
+ async getList() {
+ this.isLoading = true
+ const response = await getConversationBans(this.token)
+ this.banList = response.data.ocs.data
+ this.isLoading = false
+ },
+
+ async handleUnban(id) {
+ await unbanActor(this.token, id)
+ this.banList = this.banList.filter(ban => ban.id !== id)
+ }
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.conversation-ban {
+ &__content {
+ min-height: 250px;
+ }
+
+ &__title {
+ text-align: center;
+ }
+
+ &__list {
+ overflow: auto;
+ height: calc(100% - 45px - 12px);
+ padding: calc(var(--default-grid-baseline) * 2);
+ }
+}
+</style>
diff --git a/src/components/ConversationSettings/BanSettings/BannedItem.vue b/src/components/ConversationSettings/BanSettings/BannedItem.vue
new file mode 100644
index 000000000..cddd48399
--- /dev/null
+++ b/src/components/ConversationSettings/BanSettings/BannedItem.vue
@@ -0,0 +1,101 @@
+<!--
+ - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <li :key="ban.id" class="ban-item">
+ <div class="ban-item__header">
+ <span class="ban-item__caption">{{ ban.bannedId }}</span>
+ <div class="ban-item__buttons">
+ <NcButton type="tertiary" @click="showDetails = !showDetails">
+ {{ showDetails ? t('spreed', 'Hide details') : t('spreed', 'Show details') }}
+ </NcButton>
+ <NcButton @click="$emit('unban-participant')">
+ {{ t('spreed', 'Unban') }}
+ </NcButton>
+ </div>
+ </div>
+ <ul v-if="showDetails" class="ban-item__hint">
+ <!-- eslint-disable-next-line vue/no-v-html -->
+ <li v-for="(item, index) in banInfo" :key="index" v-html="item" />
+ </ul>
+ </li>
+</template>
+
+<script>
+import { t } from '@nextcloud/l10n'
+import moment from '@nextcloud/moment'
+
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
+
+export default {
+ name: 'BannedItem',
+
+ components: {
+ NcButton,
+ },
+
+ props: {
+ ban: {
+ type: Object,
+ required: true,
+ },
+ },
+
+ emits: ['unban-participant'],
+
+ data() {
+ return {
+ showDetails: false,
+ }
+ },
+
+ computed: {
+ banInfo() {
+ return [
+ t('spreed', '<strong>Banned by:</strong> {actor}', { actor: this.ban.actorId },
+ undefined, { escape: false, sanitize: false }),
+ t('spreed', '<strong>Date:</strong> {date}', { date: moment(this.ban.bannedTime * 1000).format('lll') },
+ undefined, { escape: false, sanitize: false }),
+ t('spreed', '<strong>Note:</strong> {note}', { note: this.ban.internalNote },
+ undefined, { escape: false, sanitize: false }),
+ ]
+ },
+ },
+
+ methods: {
+ t,
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+
+.ban-item {
+ padding: 4px 0;
+ &:not(:last-child) {
+ border-bottom: 1px solid var(--color-border);
+ }
+
+ &__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ &__caption {
+ font-weight: bold;
+ }
+
+ &__hint {
+ word-wrap: break-word;
+ color: var(--color-text-maxcontrast);
+ margin-bottom: 4px;
+ }
+
+ &__buttons {
+ display: flex;
+ }
+}
+</style>
diff --git a/src/components/ConversationSettings/ConversationSettingsDialog.vue b/src/components/ConversationSettings/ConversationSettingsDialog.vue
index 3720cc789..782e9b869 100644
--- a/src/components/ConversationSettings/ConversationSettingsDialog.vue
+++ b/src/components/ConversationSettings/ConversationSettingsDialog.vue
@@ -40,6 +40,7 @@
<LinkShareSettings v-if="!isNoteToSelf" :token="token" :can-moderate="canFullModerate" />
<RecordingConsentSettings v-if="!isNoteToSelf && recordingConsentAvailable" :token="token" :can-moderate="selfIsOwnerOrModerator" />
<ExpirationSettings :token="token" :can-moderate="selfIsOwnerOrModerator" />
+ <BanSettings v-if="supportBanV1 && canFullModerate" :token="token" />
</NcAppSettingsSection>
<!-- Meeting: lobby and sip -->
@@ -100,6 +101,7 @@ import NcAppSettingsDialog from '@nextcloud/vue/dist/Components/NcAppSettingsDia
import NcAppSettingsSection from '@nextcloud/vue/dist/Components/NcAppSettingsSection.js'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
+import BanSettings from './BanSettings/BanSettings.vue'
import BasicInfo from './BasicInfo.vue'
import BotsSettings from './BotsSettings.vue'
import BreakoutRoomsSettings from './BreakoutRoomsSettings.vue'
@@ -123,6 +125,7 @@ export default {
name: 'ConversationSettingsDialog',
components: {
+ BanSettings,
BasicInfo,
BotsSettings,
BreakoutRoomsSettings,
@@ -180,6 +183,10 @@ export default {
return (!hasTalkFeature(this.token, 'federation-v1') || !this.conversation.remoteServer)
},
+ supportBanV1() {
+ return hasTalkFeature(this.token, 'ban-v1')
+ },
+
showMediaSettings() {
return this.settingsStore.getShowMediaSettings(this.token)
},