Skip to content

Commit a0051d3

Browse files
authored
Merge pull request #11594 from nextcloud/feat/11503/admin-settings-follow-up
feat(federation): provide UI toggles in Admin settings for federation options
2 parents 4a03865 + d45bd04 commit a0051d3

File tree

2 files changed

+202
-2
lines changed

2 files changed

+202
-2
lines changed

lib/Settings/Admin/AdminSettings.php

+4
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ protected function initCommands(): void {
112112

113113
protected function initFederation(): void {
114114
$this->initialState->provideInitialState('federation_enabled', $this->serverConfig->getAppValue('spreed', 'federation_enabled', 'no'));
115+
$this->initialState->provideInitialState('federation_incoming_enabled', $this->serverConfig->getAppValue('spreed', 'federation_incoming_enabled', '1'));
116+
$this->initialState->provideInitialState('federation_outgoing_enabled', $this->serverConfig->getAppValue('spreed', 'federation_outgoing_enabled', '1'));
117+
$this->initialState->provideInitialState('federation_only_trusted_servers', $this->serverConfig->getAppValue('spreed', 'federation_only_trusted_servers', '0'));
118+
$this->initialState->provideInitialState('federation_allowed_groups', $this->serverConfig->getAppValue('spreed', 'federation_allowed_groups', '[]'));
115119
}
116120

117121
protected function initMatterbridge(): void {

src/components/AdminSettings/Federation.vue

+198-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
-->
2222

2323
<template>
24-
<section id="general_settings" class="federation section">
24+
<section id="federation_settings" class="federation section">
2525
<h2>
2626
{{ t('spreed', 'Federation') }}
2727
<small>{{ t('spreed', 'Beta') }}</small>
@@ -33,28 +33,130 @@
3333
@update:checked="saveFederationEnabled">
3434
{{ t('spreed', 'Enable Federation in Talk app') }}
3535
</NcCheckboxRadioSwitch>
36+
37+
<template v-if="isFederationEnabled">
38+
<h3>{{ t('spreed', 'Permissions') }}</h3>
39+
40+
<NcCheckboxRadioSwitch :checked="isFederationIncomingEnabled"
41+
:disabled="loading"
42+
type="switch"
43+
@update:checked="saveFederationIncomingEnabled">
44+
{{ t('spreed', 'Allow users to be invited to federated conversations') }}
45+
</NcCheckboxRadioSwitch>
46+
47+
<NcCheckboxRadioSwitch :checked="isFederationOutgoingEnabled"
48+
:disabled="loading"
49+
type="switch"
50+
@update:checked="saveFederationOutgoingEnabled">
51+
{{ t('spreed', 'Allow users to invite federated users into conversation') }}
52+
</NcCheckboxRadioSwitch>
53+
54+
<NcCheckboxRadioSwitch :checked="isFederationOnlyTrustedServersEnabled"
55+
:disabled="loading"
56+
type="switch"
57+
@update:checked="saveFederationOnlyTrustedServersEnabled">
58+
{{ t('spreed', 'Only allow to federate with trusted servers') }}
59+
</NcCheckboxRadioSwitch>
60+
<!-- eslint-disable-next-line vue/no-v-html -->
61+
<p class="settings-hint additional-top-margin" v-html="trustedServersLink" />
62+
63+
<h3>{{ t('spreed', 'Limit to groups') }}</h3>
64+
65+
<p class="settings-hint additional-top-margin">
66+
{{ t('spreed', 'When at least one group is selected, only people of the listed groups can invite federated users to conversations.') }}
67+
</p>
68+
69+
<div class="form">
70+
<NcSelect v-model="allowedGroups"
71+
input-id="allow_groups_invite_federated"
72+
:input-label="t('spreed', 'Groups allowed to invite federated users')"
73+
name="allow_groups_invite_federated"
74+
class="form__select"
75+
:options="groups"
76+
:placeholder="t('spreed', 'Select groups …')"
77+
:disabled="loading"
78+
multiple
79+
searchable
80+
:tag-width="60"
81+
:loading="loadingGroups"
82+
:show-no-options="false"
83+
:close-on-select="false"
84+
track-by="id"
85+
label="displayname"
86+
no-wrap
87+
@search-change="debounceSearchGroup" />
88+
89+
<NcButton type="primary"
90+
:disabled="loading"
91+
@click="saveAllowedGroups">
92+
{{ saveLabelAllowedGroups }}
93+
</NcButton>
94+
</div>
95+
</template>
3696
</section>
3797
</template>
3898

3999
<script>
100+
import debounce from 'debounce'
101+
102+
import axios from '@nextcloud/axios'
40103
import { loadState } from '@nextcloud/initial-state'
104+
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
41105

106+
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
42107
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
108+
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
109+
110+
const FEDERATION_ENABLED = loadState('spreed', 'federation_enabled', 'no') === 'yes'
111+
const FEDERATION_INCOMING_ENABLED = loadState('spreed', 'federation_incoming_enabled', '0') === '1'
112+
const FEDERATION_OUTGOING_ENABLED = loadState('spreed', 'federation_outgoing_enabled', '0') === '1'
113+
const FEDERATION_ONLY_TRUSTED_SERVERS = loadState('spreed', 'federation_only_trusted_servers', '0') === '1'
114+
const FEDERATION_ALLOWED_GROUPS = JSON.parse(loadState('spreed', 'federation_allowed_groups', '[]'))
43115

44116
export default {
45117
name: 'Federation',
46118

47119
components: {
120+
NcButton,
48121
NcCheckboxRadioSwitch,
122+
NcSelect,
49123
},
50124

51125
data() {
52126
return {
53127
loading: false,
54-
isFederationEnabled: loadState('spreed', 'federation_enabled') === 'yes',
128+
isFederationEnabled: FEDERATION_ENABLED,
129+
isFederationIncomingEnabled: FEDERATION_INCOMING_ENABLED,
130+
isFederationOutgoingEnabled: FEDERATION_OUTGOING_ENABLED,
131+
isFederationOnlyTrustedServersEnabled: FEDERATION_ONLY_TRUSTED_SERVERS,
132+
loadingGroups: false,
133+
groups: [],
134+
allowedGroups: [],
135+
saveLabelAllowedGroups: t('spreed', 'Save changes'),
136+
debounceSearchGroup: () => {},
55137
}
56138
},
57139

140+
computed: {
141+
trustedServersLink() {
142+
const href = generateUrl('/settings/admin/sharing#ocFederationSettings')
143+
return t('spreed', 'Trusted servers can be configured at {linkstart}Sharing settings page{linkend}.')
144+
.replace('{linkstart}', `<a target="_blank" rel="noreferrer nofollow" class="external" href="${href}">`)
145+
.replaceAll('{linkend}', ' ↗</a>')
146+
},
147+
},
148+
149+
mounted() {
150+
// allowed groups come as an array of string ids here
151+
this.allowedGroups = FEDERATION_ALLOWED_GROUPS.sort((a, b) => a.localeCompare(b))
152+
this.debounceSearchGroup = debounce(this.searchGroup, 500)
153+
this.debounceSearchGroup('')
154+
},
155+
156+
beforeDestroy() {
157+
this.debounceSearchGroup.clear?.()
158+
},
159+
58160
methods: {
59161
saveFederationEnabled(value) {
60162
this.loading = true
@@ -66,6 +168,80 @@ export default {
66168
}.bind(this),
67169
})
68170
},
171+
172+
saveFederationIncomingEnabled(value) {
173+
this.loading = true
174+
175+
OCP.AppConfig.setValue('spreed', 'federation_incoming_enabled', value ? '1' : '0', {
176+
success: function() {
177+
this.loading = false
178+
this.isFederationIncomingEnabled = value
179+
}.bind(this),
180+
})
181+
},
182+
183+
saveFederationOutgoingEnabled(value) {
184+
this.loading = true
185+
186+
OCP.AppConfig.setValue('spreed', 'federation_outgoing_enabled', value ? '1' : '0', {
187+
success: function() {
188+
this.loading = false
189+
this.isFederationOutgoingEnabled = value
190+
}.bind(this),
191+
})
192+
},
193+
194+
saveFederationOnlyTrustedServersEnabled(value) {
195+
this.loading = true
196+
197+
OCP.AppConfig.setValue('spreed', 'federation_only_trusted_servers', value ? '1' : '0', {
198+
success: function() {
199+
this.loading = false
200+
this.isFederationOnlyTrustedServersEnabled = value
201+
}.bind(this),
202+
})
203+
},
204+
205+
async searchGroup(query) {
206+
this.loadingGroups = true
207+
try {
208+
const response = await axios.get(generateOcsUrl('cloud/groups/details'), {
209+
search: query,
210+
limit: 20,
211+
offset: 0,
212+
})
213+
this.groups = response.data.ocs.data.groups.sort(function(a, b) {
214+
return a.displayname.localeCompare(b.displayname)
215+
})
216+
217+
// repopulate allowed groups with full group objects to show display name
218+
const allowedGroupIds = this.allowedGroups.map(group => typeof group === 'object' ? group.id : group)
219+
this.allowedGroups = this.groups.filter(group => allowedGroupIds.includes(group.id))
220+
} catch (err) {
221+
console.error('Could not fetch groups', err)
222+
} finally {
223+
this.loadingGroups = false
224+
}
225+
},
226+
227+
saveAllowedGroups() {
228+
this.loading = true
229+
this.loadingGroups = true
230+
this.saveLabelAllowedGroups = t('spreed', 'Saving …')
231+
232+
const groups = this.allowedGroups.map(group => typeof group === 'object' ? group.id : group)
233+
234+
OCP.AppConfig.setValue('spreed', 'federation_allowed_groups', JSON.stringify(groups), {
235+
success: function() {
236+
this.loading = false
237+
this.loadingGroups = false
238+
this.saveLabelAllowedGroups = t('spreed', 'Saved!')
239+
setTimeout(function() {
240+
this.saveLabelAllowedGroups = t('spreed', 'Save changes')
241+
}.bind(this), 5000)
242+
}.bind(this),
243+
})
244+
},
69245
},
70246
}
71247
</script>
@@ -77,4 +253,24 @@ small {
77253
border-radius: 16px;
78254
padding: 0 9px;
79255
}
256+
257+
h3 {
258+
margin-top: 24px;
259+
font-weight: bold;
260+
}
261+
262+
.additional-top-margin {
263+
margin-top: 10px;
264+
}
265+
266+
.form {
267+
display: flex;
268+
align-items: flex-end;
269+
gap: 10px;
270+
padding-top: 5px;
271+
272+
&__select {
273+
min-width: 300px !important;
274+
}
275+
}
80276
</style>

0 commit comments

Comments
 (0)