Skip to content

Commit eea743b

Browse files
matsaurbromiesTM
andcommitted
feat(aliases): add admin setting to disable alias creation
Introduces an `allow_new_mail_aliases` app config flag (default: yes) that lets administrators prevent users from creating new mail aliases. - Backend: guard in AliasesService::create() throws ClientException when disabled - Admin UI: toggle switch in AdminSettings, mirroring the existing "allow new mail accounts" setting - Frontend: hides the "Add alias" button when disabled - Exposed via PageController initial state and storable via occ config:app:set Extends existing unit tests for AliasesService, AdminSettings, and PageController to cover the new setting. AI-assisted: Claude Code (Claude Sonnet 4.6) Co-Authored-By: Kai Henseler <kai.henseler@strato.de> Signed-off-by: Matthias Sauer <sauerm@strato.de>
1 parent 195e435 commit eea743b

14 files changed

Lines changed: 122 additions & 9 deletions

File tree

appinfo/routes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,11 @@
345345
'url' => '/api/settings/allownewaccounts',
346346
'verb' => 'POST'
347347
],
348+
[
349+
'name' => 'settings#setAllowNewMailAliases',
350+
'url' => '/api/settings/allownewaliases',
351+
'verb' => 'POST'
352+
],
348353
[
349354
'name' => 'settings#setEnabledLlmProcessing',
350355
'url' => '/api/settings/llm',

lib/Controller/PageController.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ public function index(): TemplateResponse {
304304
$this->config->getAppValue('mail', 'allow_new_mail_accounts', 'yes') === 'yes'
305305
);
306306

307+
$this->initialStateService->provideInitialState(
308+
'allow-new-aliases',
309+
$this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'yes'
310+
);
311+
307312
$this->initialStateService->provideInitialState(
308313
'llm_summaries_available',
309314
$this->aiIntegrationsService->isLlmProcessingEnabled() && $this->aiIntegrationsService->isLlmAvailable(SummaryTaskType::class)

lib/Controller/SettingsController.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public function setAllowNewMailAccounts(bool $allowed): void {
114114
$this->config->setAppValue('mail', 'allow_new_mail_accounts', $allowed ? 'yes' : 'no');
115115
}
116116

117+
public function setAllowNewMailAliases(bool $allowed): JSONResponse {
118+
$this->config->setAppValue('mail', 'allow_new_mail_aliases', $allowed ? 'yes' : 'no');
119+
return new JSONResponse([]);
120+
}
121+
117122
public function setEnabledLlmProcessing(bool $enabled): JSONResponse {
118123
$this->config->setAppValue('mail', 'llm_processing', $enabled ? 'yes' : 'no');
119124
return new JSONResponse([]);

lib/Service/AliasesService.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,21 @@
1515
use OCA\Mail\Db\MailAccountMapper;
1616
use OCA\Mail\Exception\ClientException;
1717
use OCP\AppFramework\Db\DoesNotExistException;
18+
use OCP\IConfig;
1819

1920
class AliasesService {
2021
/** @var AliasMapper */
2122
private $aliasMapper;
2223

2324
/** @var MailAccountMapper */
2425
private $mailAccountMapper;
26+
/** @var IConfig */
27+
private $config;
2528

26-
public function __construct(AliasMapper $aliasMapper, MailAccountMapper $mailAccountMapper) {
29+
public function __construct(AliasMapper $aliasMapper, MailAccountMapper $mailAccountMapper, IConfig $config) {
2730
$this->aliasMapper = $aliasMapper;
2831
$this->mailAccountMapper = $mailAccountMapper;
32+
$this->config = $config;
2933
}
3034

3135
/**
@@ -67,6 +71,10 @@ public function findByAliasAndUserId(string $aliasEmail, string $userId): Alias
6771
* @throws DoesNotExistException
6872
*/
6973
public function create(string $userId, int $accountId, string $alias, string $aliasName): Alias {
74+
if ($this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'no') {
75+
throw new ClientException('Creating aliases has been disabled by the administrator.');
76+
}
77+
7078
$this->mailAccountMapper->find($userId, $accountId);
7179

7280
$aliasEntity = new Alias();

lib/Settings/AdminSettings.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ public function getForm() {
8282
$this->config->getAppValue('mail', 'allow_new_mail_accounts', 'yes') === 'yes'
8383
);
8484

85+
$this->initialStateService->provideInitialState(
86+
Application::APP_ID,
87+
'allow_new_mail_aliases',
88+
$this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'yes'
89+
);
90+
8591
$this->initialStateService->provideInitialState(
8692
Application::APP_ID,
8793
'layout_message_view',

src/components/AccountSettings.vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@
1111
:additional-trap-elements="trapElements"
1212
:name="t('mail', 'Account settings')"
1313
@update:open="updateOpen">
14-
<AppSettingsSection
14+
<AppSettingsSection v-if="showProviderAppPassword"
15+
id="provider-app-password"
16+
:name="t('mail', 'IMAP access / password')">
17+
<ProviderAppPassword :account="account" :provider-id="account.managedByProvider" />
18+
</AppSettingsSection>
19+
<AppSettingsSection v-if="allowNewAliases"
1520
id="alias-settings"
1621
:name="t('mail', 'Aliases')">
1722
<AliasSettings :account="account" @rename-primary-alias="scrollToAccountSettings" />
@@ -209,6 +214,16 @@ export default {
209214
email() {
210215
return this.account.emailAddress
211216
},
217+
allowNewAliases() {
218+
return this.mainStore.getPreference('allow-new-aliases', true)
219+
},
220+
showProviderAppPassword() {
221+
// Show the password reset section if:
222+
// 1. Account is managed by a provider (managedByProvider is set)
223+
// 2. Provider supports app passwords
224+
return this.account.managedByProvider
225+
&& this.account.providerCapabilities?.appPasswords === true
226+
},
212227
},
213228
214229
watch: {

src/components/AliasSettings.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353

5454
<div v-if="!account.provisioningId" class="aliases-controls">
5555
<ButtonVue
56-
v-if="!showForm"
56+
v-if="!showForm && allowNewAliases"
5757
type="primary"
5858
:aria-label="t('mail', 'Add alias')"
5959
@click="showForm = true">
@@ -125,7 +125,9 @@ export default {
125125
aliases() {
126126
return this.account.aliases
127127
},
128-
128+
allowNewAliases() {
129+
return this.mainStore.getPreference('allow-new-aliases', true)
130+
},
129131
accountAlias() {
130132
return {
131133
alias: this.account.emailAddress,

src/components/settings/AdminSettings.vue

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@
136136
</p>
137137
</article>
138138
</div>
139+
<div class="app-description">
140+
<h3>{{ t('mail', 'Allow aliases') }}</h3>
141+
<article>
142+
<p>
143+
<NcCheckboxRadioSwitch :checked.sync="allowNewMailAliases"
144+
type="switch"
145+
@update:checked="updateAllowNewMailAliases">
146+
{{ t('mail', 'Allow users to create mail aliases') }}
147+
</NcCheckboxRadioSwitch>
148+
</p>
149+
</article>
150+
</div>
139151
<div
140152
v-if="isLlmSummaryConfigured"
141153
class="app-description">
@@ -300,6 +312,7 @@ import {
300312
setImportanceClassificationEnabledByDefault,
301313
setLayoutMessageView,
302314
updateAllowNewMailAccounts,
315+
updateAllowNewMailAliases,
303316
updateEnabledSmartReply,
304317
updateLlmEnabled,
305318
updateProvisioningSettings,
@@ -368,6 +381,7 @@ export default {
368381
},
369382
370383
allowNewMailAccounts: loadState('mail', 'allow_new_mail_accounts', true),
384+
allowNewMailAliases: loadState('mail', 'allow_new_mail_aliases', true),
371385
isLlmSummaryConfigured: loadState('mail', 'enabled_llm_summary_backend'),
372386
isLlmEnabled: loadState('mail', 'llm_processing', true),
373387
isLlmFreePromptConfigured: loadState('mail', 'enabled_llm_free_prompt_backend'),
@@ -431,6 +445,9 @@ export default {
431445
async updateAllowNewMailAccounts(checked) {
432446
await updateAllowNewMailAccounts(checked)
433447
},
448+
async updateAllowNewMailAliases(checked) {
449+
await updateAllowNewMailAliases(checked)
450+
},
434451
435452
async updateLlmEnabled(checked) {
436453
await updateLlmEnabled(checked)

src/init.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ export default function initAfterAppCreation() {
6969
key: 'allow-new-accounts',
7070
value: loadState('mail', 'allow-new-accounts', true),
7171
})
72+
mainStore.savePreferenceMutation({
73+
key: 'allow-new-aliases',
74+
value: loadState('mail', 'allow-new-aliases', true),
75+
})
7276
mainStore.savePreferenceMutation({
7377
key: 'password-is-unavailable',
7478
value: loadState('mail', 'password-is-unavailable', false),

src/service/SettingsService.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ export function updateAllowNewMailAccounts(allowed) {
6161
return axios.post(url, data).then((resp) => resp.data)
6262
}
6363

64+
export function updateAllowNewMailAliases(allowed) {
65+
const url = generateUrl('/apps/mail/api/settings/allownewaliases')
66+
const data = {
67+
allowed,
68+
}
69+
return axios.post(url, data).then((resp) => resp.data)
70+
}
71+
6472
export async function updateLlmEnabled(enabled) {
6573
const url = generateUrl('/apps/mail/api/settings/llm')
6674
const data = {

0 commit comments

Comments
 (0)