Skip to content
Open
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
5 changes: 5 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@
'url' => '/api/settings/allownewaccounts',
'verb' => 'POST'
],
[
'name' => 'settings#setAllowNewMailAliases',
'url' => '/api/settings/allownewaliases',
'verb' => 'POST'
],
[
'name' => 'settings#setEnabledLlmProcessing',
'url' => '/api/settings/llm',
Expand Down
5 changes: 5 additions & 0 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ public function index(): TemplateResponse {
$this->config->getAppValue('mail', 'allow_new_mail_accounts', 'yes') === 'yes'
);

$this->initialStateService->provideInitialState(
'allow-new-aliases',
$this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'yes'
);

$this->initialStateService->provideInitialState(
'llm_summaries_available',
$this->aiIntegrationsService->isLlmProcessingEnabled() && $this->aiIntegrationsService->isLlmAvailable(SummaryTaskType::class)
Expand Down
5 changes: 5 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ public function setAllowNewMailAccounts(bool $allowed): void {
$this->config->setAppValue('mail', 'allow_new_mail_accounts', $allowed ? 'yes' : 'no');
}

public function setAllowNewMailAliases(bool $allowed): JSONResponse {
$this->config->setAppValue('mail', 'allow_new_mail_aliases', $allowed ? 'yes' : 'no');
return new JSONResponse([]);
}

public function setEnabledLlmProcessing(bool $enabled): JSONResponse {
$this->config->setAppValue('mail', 'llm_processing', $enabled ? 'yes' : 'no');
return new JSONResponse([]);
Expand Down
10 changes: 9 additions & 1 deletion lib/Service/AliasesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@
use OCA\Mail\Db\MailAccountMapper;
use OCA\Mail\Exception\ClientException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IConfig;

class AliasesService {
/** @var AliasMapper */
private $aliasMapper;

/** @var MailAccountMapper */
private $mailAccountMapper;
/** @var IConfig */
private $config;

public function __construct(AliasMapper $aliasMapper, MailAccountMapper $mailAccountMapper) {
public function __construct(AliasMapper $aliasMapper, MailAccountMapper $mailAccountMapper, IConfig $config) {
$this->aliasMapper = $aliasMapper;
$this->mailAccountMapper = $mailAccountMapper;
$this->config = $config;
}

/**
Expand Down Expand Up @@ -67,6 +71,10 @@ public function findByAliasAndUserId(string $aliasEmail, string $userId): Alias
* @throws DoesNotExistException
*/
public function create(string $userId, int $accountId, string $alias, string $aliasName): Alias {
if ($this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'no') {
throw new ClientException('Creating aliases has been disabled by the administrator.');
}

$this->mailAccountMapper->find($userId, $accountId);

$aliasEntity = new Alias();
Expand Down
6 changes: 6 additions & 0 deletions lib/Settings/AdminSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public function getForm() {
$this->config->getAppValue('mail', 'allow_new_mail_accounts', 'yes') === 'yes'
);

$this->initialStateService->provideInitialState(
Application::APP_ID,
'allow_new_mail_aliases',
$this->config->getAppValue('mail', 'allow_new_mail_aliases', 'yes') === 'yes'
);

$this->initialStateService->provideInitialState(
Application::APP_ID,
'layout_message_view',
Expand Down
5 changes: 5 additions & 0 deletions src/components/AccountSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
:name="t('mail', 'Account settings')"
@update:open="updateOpen">
<AppSettingsSection
v-if="allowNewAliases"
id="alias-settings"
:name="t('mail', 'Aliases')">
<AliasSettings :account="account" @rename-primary-alias="scrollToAccountSettings" />
Expand Down Expand Up @@ -85,14 +86,14 @@
id="mail-filters"
:name="t('mail', 'Filters')">
<div id="mail-filters">
<MailFilters :key="account.accountId" ref="mailFilters" :account="account" />

Check warning on line 89 in src/components/AccountSettings.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'mailFilters' is defined as ref, but never used
</div>
</AppSettingsSection>
<AppSettingsSection
v-if="account"
id="quick-actions-settings"
:name="t('mail', 'Quick actions')">
<Settings :key="account.accountId" ref="quickActions" :account="account" />

Check warning on line 96 in src/components/AccountSettings.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'quickActions' is defined as ref, but never used
</AppSettingsSection>
<AppSettingsSection
v-if="account && account.sieveEnabled"
Expand All @@ -101,7 +102,7 @@
<div id="sieve-filter">
<SieveFilterForm
:key="account.accountId"
ref="sieveFilterForm"

Check warning on line 105 in src/components/AccountSettings.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'sieveFilterForm' is defined as ref, but never used
:account="account" />
</div>
</AppSettingsSection>
Expand All @@ -125,7 +126,7 @@
<div id="sieve-settings">
<SieveAccountForm
:key="account.accountId"
ref="sieveAccountForm"

Check warning on line 129 in src/components/AccountSettings.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'sieveAccountForm' is defined as ref, but never used
:account="account" />
</div>
</AppSettingsSection>
Expand Down Expand Up @@ -209,10 +210,14 @@
email() {
return this.account.emailAddress
},

allowNewAliases() {
return this.mainStore.getPreference('allow-new-aliases', true)
},
},

watch: {
open(newState, oldState) {

Check warning on line 220 in src/components/AccountSettings.vue

View workflow job for this annotation

GitHub Actions / NPM lint

'oldState' is defined but never used
if (newState === true && this.fetchActiveSieveScript === true) {
logger.debug(`Load active sieve script for account ${this.account.accountId}`)
this.fetchActiveSieveScript = false
Expand Down
6 changes: 5 additions & 1 deletion src/components/AliasSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

<div v-if="!account.provisioningId" class="aliases-controls">
<ButtonVue
v-if="!showForm"
v-if="!showForm && allowNewAliases"
type="primary"
:aria-label="t('mail', 'Add alias')"
@click="showForm = true">
Expand Down Expand Up @@ -126,6 +126,10 @@ export default {
return this.account.aliases
},

allowNewAliases() {
return this.mainStore.getPreference('allow-new-aliases', true)
},

accountAlias() {
return {
alias: this.account.emailAddress,
Expand Down
21 changes: 21 additions & 0 deletions src/components/settings/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@
</p>
</article>
</div>
<div class="app-description">
<h3>{{ t('mail', 'Allow aliases') }}</h3>
<article>
<p>
{{ t('mail', 'The Mail app does not verify aliases. If this is enabled without existing server-side support, your mail server will likely reject outgoing messages, causing emails to fail.') }}
</p>
<p>
<NcCheckboxRadioSwitch v-model="allowNewMailAliases"
type="switch"
@update:checked="updateAllowNewMailAliases">
{{ t('mail', 'Allow users to create mail aliases') }}
</NcCheckboxRadioSwitch>
</p>
</article>
</div>
<div
v-if="isLlmSummaryConfigured"
class="app-description">
Expand Down Expand Up @@ -300,6 +315,7 @@ import {
setImportanceClassificationEnabledByDefault,
setLayoutMessageView,
updateAllowNewMailAccounts,
updateAllowNewMailAliases,
updateEnabledSmartReply,
updateLlmEnabled,
updateProvisioningSettings,
Expand Down Expand Up @@ -368,6 +384,7 @@ export default {
},

allowNewMailAccounts: loadState('mail', 'allow_new_mail_accounts', true),
allowNewMailAliases: loadState('mail', 'allow_new_mail_aliases', true),
isLlmSummaryConfigured: loadState('mail', 'enabled_llm_summary_backend'),
isLlmEnabled: loadState('mail', 'llm_processing', true),
isLlmFreePromptConfigured: loadState('mail', 'enabled_llm_free_prompt_backend'),
Expand Down Expand Up @@ -432,6 +449,10 @@ export default {
await updateAllowNewMailAccounts(checked)
},

async updateAllowNewMailAliases(checked) {
await updateAllowNewMailAliases(checked)
},

async updateLlmEnabled(checked) {
await updateLlmEnabled(checked)
},
Expand Down
4 changes: 4 additions & 0 deletions src/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export default function initAfterAppCreation() {
key: 'allow-new-accounts',
value: loadState('mail', 'allow-new-accounts', true),
})
mainStore.savePreferenceMutation({
key: 'allow-new-aliases',
value: loadState('mail', 'allow-new-aliases', true),
})
mainStore.savePreferenceMutation({
key: 'password-is-unavailable',
value: loadState('mail', 'password-is-unavailable', false),
Expand Down
8 changes: 8 additions & 0 deletions src/service/SettingsService.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ export function updateAllowNewMailAccounts(allowed) {
return axios.post(url, data).then((resp) => resp.data)
}

export function updateAllowNewMailAliases(allowed) {
const url = generateUrl('/apps/mail/api/settings/allownewaliases')
const data = {
allowed,
}
return axios.post(url, data).then((resp) => resp.data)
}

export async function updateLlmEnabled(enabled) {
const url = generateUrl('/apps/mail/api/settings/llm')
const data = {
Expand Down
7 changes: 6 additions & 1 deletion tests/Unit/Controller/AliasesControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IConfig;

class AliasesControllerTest extends TestCase {
private $controller;
Expand Down Expand Up @@ -46,8 +47,12 @@ public function setUp(): void {

$this->aliasMapper = $this->createMock(AliasMapper::class);
$this->mailAccountMapper = $this->createMock(MailAccountMapper::class);
$config = $this->createMock(IConfig::class);
$config->method('getAppValue')
->with('mail', 'allow_new_mail_aliases', 'yes')
->willReturn('yes');

$this->aliasService = new AliasesService($this->aliasMapper, $this->mailAccountMapper);
$this->aliasService = new AliasesService($this->aliasMapper, $this->mailAccountMapper, $config);
$this->controller = new AliasesController($this->appName, $this->request, $this->aliasService, $this->userId);
}

Expand Down
5 changes: 3 additions & 2 deletions tests/Unit/Controller/PageControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public function testIndex(): void {
['version', '0.0.0', '26.0.0'],
['app.mail.attachment-size-limit', 0, 123],
]);
$this->config->expects($this->exactly(7))
$this->config->expects($this->exactly(8))
->method('getAppValue')
->withConsecutive(
[ 'mail', 'installed_version' ],
Expand All @@ -279,6 +279,7 @@ public function testIndex(): void {
['mail', 'microsoft_oauth_tenant_id' ],
['core', 'backgroundjobs_mode', 'ajax' ],
['mail', 'allow_new_mail_accounts', 'yes'],
['mail', 'allow_new_mail_aliases', 'yes'],
)->willReturnOnConsecutiveCalls(
$this->returnValue('1.2.3'),
$this->returnValue('threaded'),
Expand All @@ -287,7 +288,7 @@ public function testIndex(): void {
$this->returnValue(''),
$this->returnValue('cron'),
$this->returnValue('yes'),
$this->returnValue('no')
$this->returnValue('yes'),
);
$this->aiIntegrationsService->expects(self::exactly(4))
->method('isLlmProcessingEnabled')
Expand Down
29 changes: 28 additions & 1 deletion tests/Unit/Service/AliasesServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use OCA\Mail\Exception\ClientException;
use OCA\Mail\Service\AliasesService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IConfig;

class AliasesServiceTest extends TestCase {
/** @var AliasesService */
Expand All @@ -28,15 +29,24 @@ class AliasesServiceTest extends TestCase {
/** @var MailAccountMapper */
private $mailAccountMapper;

/** @var IConfig */
private $config;

protected function setUp(): void {
parent::setUp();

$this->aliasMapper = $this->createMock(AliasMapper::class);
$this->mailAccountMapper = $this->createMock(MailAccountMapper::class);
$this->config = $this->createMock(IConfig::class);

$this->config->method('getAppValue')
->with('mail', 'allow_new_mail_aliases', 'yes')
->willReturn('yes');

$this->service = new AliasesService(
$this->aliasMapper,
$this->mailAccountMapper
$this->mailAccountMapper,
$this->config,
);
}

Expand Down Expand Up @@ -123,6 +133,23 @@ public function testCreateForbiddenAccountId(): void {
);
}

public function testCreateDisabledByAdmin(): void {
$this->expectException(ClientException::class);
$this->expectExceptionMessage('Creating aliases has been disabled by the administrator.');

$this->config->expects(self::once())
->method('getAppValue')
->with('mail', 'allow_new_mail_aliases', 'yes')
->willReturn('no');

$this->mailAccountMapper->expects(self::never())
->method('find');
$this->aliasMapper->expects(self::never())
->method('insert');

$this->service->create(300, 200, 'jane@doe.com', 'Jane Doe');
}

public function testDelete(): void {
$entity = new Alias();
$entity->setId(101);
Expand Down
7 changes: 6 additions & 1 deletion tests/Unit/Settings/AdminSettingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function testGetSection() {
}

public function testGetForm() {
$this->serviceMock->getParameter('initialStateService')->expects($this->exactly(14))
$this->serviceMock->getParameter('initialStateService')->expects($this->exactly(15))
->method('provideInitialState')
->withConsecutive(
[
Expand All @@ -55,6 +55,11 @@ public function testGetForm() {
'allow_new_mail_accounts',
$this->anything()
],
[
Application::APP_ID,
'allow_new_mail_aliases',
$this->anything()
],
[
Application::APP_ID,
'layout_message_view',
Expand Down
Loading