Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(federation): provide UI toggles in Admin settings for federation options #11594

Merged
merged 1 commit into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/Settings/Admin/AdminSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ protected function initCommands(): void {

protected function initFederation(): void {
$this->initialState->provideInitialState('federation_enabled', $this->serverConfig->getAppValue('spreed', 'federation_enabled', 'no'));
$this->initialState->provideInitialState('federation_incoming_enabled', $this->serverConfig->getAppValue('spreed', 'federation_incoming_enabled', '1'));
$this->initialState->provideInitialState('federation_outgoing_enabled', $this->serverConfig->getAppValue('spreed', 'federation_outgoing_enabled', '1'));
$this->initialState->provideInitialState('federation_only_trusted_servers', $this->serverConfig->getAppValue('spreed', 'federation_only_trusted_servers', '0'));
$this->initialState->provideInitialState('federation_allowed_groups', $this->serverConfig->getAppValue('spreed', 'federation_allowed_groups', '[]'));
}

protected function initMatterbridge(): void {
Expand Down
200 changes: 198 additions & 2 deletions src/components/AdminSettings/Federation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
-->

<template>
<section id="general_settings" class="federation section">
<section id="federation_settings" class="federation section">
<h2>
{{ t('spreed', 'Federation') }}
<small>{{ t('spreed', 'Beta') }}</small>
Expand All @@ -33,28 +33,130 @@
@update:checked="saveFederationEnabled">
{{ t('spreed', 'Enable Federation in Talk app') }}
</NcCheckboxRadioSwitch>

<template v-if="isFederationEnabled">
<h3>{{ t('spreed', 'Permissions') }}</h3>

<NcCheckboxRadioSwitch :checked="isFederationIncomingEnabled"
:disabled="loading"
type="switch"
@update:checked="saveFederationIncomingEnabled">
{{ t('spreed', 'Allow users to be invited to federated conversations') }}
</NcCheckboxRadioSwitch>

<NcCheckboxRadioSwitch :checked="isFederationOutgoingEnabled"
:disabled="loading"
type="switch"
@update:checked="saveFederationOutgoingEnabled">
{{ t('spreed', 'Allow users to invite federated users into conversation') }}
</NcCheckboxRadioSwitch>

<NcCheckboxRadioSwitch :checked="isFederationOnlyTrustedServersEnabled"
:disabled="loading"
type="switch"
@update:checked="saveFederationOnlyTrustedServersEnabled">
{{ t('spreed', 'Only allow to federate with trusted servers') }}
</NcCheckboxRadioSwitch>
<!-- eslint-disable-next-line vue/no-v-html -->
<p class="settings-hint additional-top-margin" v-html="trustedServersLink" />

<h3>{{ t('spreed', 'Limit to groups') }}</h3>

<p class="settings-hint additional-top-margin">
{{ t('spreed', 'When at least one group is selected, only people of the listed groups can invite federated users to conversations.') }}
</p>

<div class="form">
<NcSelect v-model="allowedGroups"
input-id="allow_groups_invite_federated"
:input-label="t('spreed', 'Groups allowed to invite federated users')"
name="allow_groups_invite_federated"
class="form__select"
:options="groups"
:placeholder="t('spreed', 'Select groups …')"
:disabled="loading"
multiple
searchable
:tag-width="60"
:loading="loadingGroups"
:show-no-options="false"
:close-on-select="false"
track-by="id"
label="displayname"
no-wrap
@search-change="debounceSearchGroup" />

<NcButton type="primary"
:disabled="loading"
@click="saveAllowedGroups">
{{ saveLabelAllowedGroups }}
</NcButton>
</div>
</template>
</section>
</template>

<script>
import debounce from 'debounce'

import axios from '@nextcloud/axios'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl, generateUrl } from '@nextcloud/router'

import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'

const FEDERATION_ENABLED = loadState('spreed', 'federation_enabled', 'no') === 'yes'
const FEDERATION_INCOMING_ENABLED = loadState('spreed', 'federation_incoming_enabled', '0') === '1'
const FEDERATION_OUTGOING_ENABLED = loadState('spreed', 'federation_outgoing_enabled', '0') === '1'
const FEDERATION_ONLY_TRUSTED_SERVERS = loadState('spreed', 'federation_only_trusted_servers', '0') === '1'
const FEDERATION_ALLOWED_GROUPS = JSON.parse(loadState('spreed', 'federation_allowed_groups', '[]'))

export default {
name: 'Federation',

components: {
NcButton,
NcCheckboxRadioSwitch,
NcSelect,
},

data() {
return {
loading: false,
isFederationEnabled: loadState('spreed', 'federation_enabled') === 'yes',
isFederationEnabled: FEDERATION_ENABLED,
isFederationIncomingEnabled: FEDERATION_INCOMING_ENABLED,
isFederationOutgoingEnabled: FEDERATION_OUTGOING_ENABLED,
isFederationOnlyTrustedServersEnabled: FEDERATION_ONLY_TRUSTED_SERVERS,
loadingGroups: false,
groups: [],
allowedGroups: [],
saveLabelAllowedGroups: t('spreed', 'Save changes'),
debounceSearchGroup: () => {},
}
},

computed: {
trustedServersLink() {
const href = generateUrl('/settings/admin/sharing#ocFederationSettings')
return t('spreed', 'Trusted servers can be configured at {linkstart}Sharing settings page{linkend}.')
.replace('{linkstart}', `<a target="_blank" rel="noreferrer nofollow" class="external" href="${href}">`)
.replaceAll('{linkend}', ' ↗</a>')
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
},
},

mounted() {
// allowed groups come as an array of string ids here
this.allowedGroups = FEDERATION_ALLOWED_GROUPS.sort((a, b) => a.localeCompare(b))
this.debounceSearchGroup = debounce(this.searchGroup, 500)
this.debounceSearchGroup('')
},

beforeDestroy() {
this.debounceSearchGroup.clear?.()
},

methods: {
saveFederationEnabled(value) {
this.loading = true
Expand All @@ -66,6 +168,80 @@ export default {
}.bind(this),
})
},

saveFederationIncomingEnabled(value) {
this.loading = true

OCP.AppConfig.setValue('spreed', 'federation_incoming_enabled', value ? '1' : '0', {
success: function() {
this.loading = false
this.isFederationIncomingEnabled = value
}.bind(this),
})
},

saveFederationOutgoingEnabled(value) {
this.loading = true

OCP.AppConfig.setValue('spreed', 'federation_outgoing_enabled', value ? '1' : '0', {
success: function() {
this.loading = false
this.isFederationOutgoingEnabled = value
}.bind(this),
})
},

saveFederationOnlyTrustedServersEnabled(value) {
this.loading = true

OCP.AppConfig.setValue('spreed', 'federation_only_trusted_servers', value ? '1' : '0', {
success: function() {
this.loading = false
this.isFederationOnlyTrustedServersEnabled = value
}.bind(this),
})
},

async searchGroup(query) {
this.loadingGroups = true
try {
const response = await axios.get(generateOcsUrl('cloud/groups/details'), {
search: query,
limit: 20,
offset: 0,
})
this.groups = response.data.ocs.data.groups.sort(function(a, b) {
return a.displayname.localeCompare(b.displayname)
})

// repopulate allowed groups with full group objects to show display name
const allowedGroupIds = this.allowedGroups.map(group => typeof group === 'object' ? group.id : group)
this.allowedGroups = this.groups.filter(group => allowedGroupIds.includes(group.id))
} catch (err) {
console.error('Could not fetch groups', err)
} finally {
this.loadingGroups = false
}
},

saveAllowedGroups() {
this.loading = true
this.loadingGroups = true
this.saveLabelAllowedGroups = t('spreed', 'Saving …')

const groups = this.allowedGroups.map(group => typeof group === 'object' ? group.id : group)

OCP.AppConfig.setValue('spreed', 'federation_allowed_groups', JSON.stringify(groups), {
success: function() {
this.loading = false
this.loadingGroups = false
this.saveLabelAllowedGroups = t('spreed', 'Saved!')
setTimeout(function() {
this.saveLabelAllowedGroups = t('spreed', 'Save changes')
}.bind(this), 5000)
}.bind(this),
})
},
},
}
</script>
Expand All @@ -77,4 +253,24 @@ small {
border-radius: 16px;
padding: 0 9px;
}

h3 {
margin-top: 24px;
font-weight: bold;
}

.additional-top-margin {
margin-top: 10px;
}

.form {
display: flex;
align-items: flex-end;
gap: 10px;
padding-top: 5px;

&__select {
min-width: 300px !important;
}
}
</style>
Loading