Persist provisioned accounts
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
Родитель
26c13bc035
Коммит
ad29c8a46c
|
@ -12,7 +12,7 @@
|
|||
- **🙈 We’re not reinventing the wheel!** Based on the great [Horde](http://horde.org) libraries.
|
||||
- **📬 Want to host your own mail server?** We don’t have to reimplement this as you could set up [Mail-in-a-Box](https://mailinabox.email)!
|
||||
]]></description>
|
||||
<version>0.19.1</version>
|
||||
<version>0.20.0</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Christoph Wurst</author>
|
||||
<author>Jan-Christoph Borchardt</author>
|
||||
|
@ -34,10 +34,15 @@
|
|||
<repair-steps>
|
||||
<post-migration>
|
||||
<step>OCA\Mail\Migration\FixCollectedAddresses</step>
|
||||
<step>OCA\Mail\Migration\MigrateProvisioningConfig</step>
|
||||
<step>OCA\Mail\Migration\ProvisionAccounts</step>
|
||||
</post-migration>
|
||||
</repair-steps>
|
||||
<commands>
|
||||
<command>OCA\Mail\Command\CreateAccount</command>
|
||||
<command>OCA\Mail\Command\ExportAccount</command>
|
||||
</commands>
|
||||
<settings>
|
||||
<admin>OCA\Mail\Settings\AdminSettings</admin>
|
||||
</settings>
|
||||
</info>
|
||||
|
|
|
@ -113,6 +113,16 @@ return [
|
|||
'url' => '/proxy',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#provisioning',
|
||||
'url' => '/api/settings/provisioning',
|
||||
'verb' => 'POST'
|
||||
],
|
||||
[
|
||||
'name' => 'settings#deprovision',
|
||||
'url' => '/api/settings/provisioning',
|
||||
'verb' => 'DELETE'
|
||||
],
|
||||
],
|
||||
'resources' => [
|
||||
'accounts' => ['url' => '/api/accounts'],
|
||||
|
|
46
doc/admin.md
46
doc/admin.md
|
@ -9,52 +9,6 @@ Then open the Mail app from the app menu. Put in your mail account credentials a
|
|||
|
||||
Certain advanced or experimental features need to be specifically enabled in your `config.php`:
|
||||
|
||||
### Automatic account creation
|
||||
|
||||
In cases where an external user back-end is used for both your Nextcloud and your mail server you may want to have imap accounts set up automatically for your users.
|
||||
|
||||
### Available patterns
|
||||
|
||||
Two patterns are available to automatically construct credentials:
|
||||
* `%USERID%`, e.g. `jan`
|
||||
* `%EMAIL%`, e.g. `jan@domain.tld`
|
||||
|
||||
### Minimal configuration
|
||||
|
||||
The following minimal configuration will add such an account as soon as the user logs in. The login password is used for the IMAP and SMTP authentication.
|
||||
|
||||
Note: Valid values for SSL are `'none'`, `'ssl'` and `'tls'`.
|
||||
|
||||
```
|
||||
'app.mail.accounts.default' => [
|
||||
'email' => '%USERID%@domain.tld',
|
||||
'imapHost' => 'imap.domain.tld',
|
||||
'imapPort' => 993,
|
||||
'imapSslMode' => 'ssl',
|
||||
'smtpHost' => 'smtp.domain.tld',
|
||||
'smtpPort' => 486,
|
||||
'smtpSslMode' => 'tls',
|
||||
],
|
||||
```
|
||||
|
||||
### Advanced configuration
|
||||
|
||||
In case you have to tweak IMAP and SMTP username, you can do that too.
|
||||
|
||||
```
|
||||
'app.mail.accounts.default' => [
|
||||
'email' => '%USERID%@domain.tld',
|
||||
'imapHost' => 'imap.domain.tld',
|
||||
'imapPort' => 993,
|
||||
'imapUser' => '%USERID%@domain.tld',
|
||||
'imapSslMode' => 'ssl',
|
||||
'smtpHost' => 'smtp.domain.tld',
|
||||
'smtpPort' => 486,
|
||||
'smtpUser' => '%USERID%@domain.tld',
|
||||
'smtpSslMode' => 'tls',
|
||||
],
|
||||
```
|
||||
|
||||
### Timeouts
|
||||
Depending on your mail host, it may be necessary to increase your IMAP and/or SMTP timeout threshold. Currently IMAP defaults to 20 seconds and SMTP defaults to 2 seconds. They can be changed as follows:
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
namespace OCA\Mail\AppInfo;
|
||||
|
||||
use OC\Hooks\PublicEmitter;
|
||||
use OCA\Mail\Contracts\IAttachmentService;
|
||||
use OCA\Mail\Contracts\IAvatarService;
|
||||
use OCA\Mail\Contracts\IMailManager;
|
||||
|
@ -34,6 +35,7 @@ use OCA\Mail\Events\DraftSavedEvent;
|
|||
use OCA\Mail\Events\MessageSentEvent;
|
||||
use OCA\Mail\Events\SaveDraftEvent;
|
||||
use OCA\Mail\Http\Middleware\ErrorMiddleware;
|
||||
use OCA\Mail\Http\Middleware\ProvisioningMiddleware;
|
||||
use OCA\Mail\Listener\AddressCollectionListener;
|
||||
use OCA\Mail\Listener\DeleteDraftListener;
|
||||
use OCA\Mail\Listener\DraftMailboxCreatorListener;
|
||||
|
@ -50,7 +52,8 @@ use OCA\Mail\Service\MailTransmission;
|
|||
use OCA\Mail\Service\UserPreferenceSevice;
|
||||
use OCP\AppFramework\IAppContainer;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IContainer;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Util;
|
||||
|
||||
class BootstrapSingleton {
|
||||
|
@ -108,6 +111,7 @@ class BootstrapSingleton {
|
|||
|
||||
$container->registerAlias('ErrorMiddleware', ErrorMiddleware::class);
|
||||
$container->registerMiddleWare('ErrorMiddleware');
|
||||
$container->registerMiddleWare(ProvisioningMiddleware::class);
|
||||
|
||||
$container->registerAlias(IGroupService::class, NextcloudGroupService::class);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Controller;
|
||||
|
||||
use OCA\Mail\AppInfo\Application;
|
||||
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\IRequest;
|
||||
|
||||
class SettingsController extends Controller {
|
||||
|
||||
/** @var ProvisioningManager */
|
||||
private $provisioningManager;
|
||||
|
||||
public function __construct(IRequest $request,
|
||||
ProvisioningManager $provisioningManager) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->provisioningManager = $provisioningManager;
|
||||
}
|
||||
|
||||
public function provisioning(string $emailTemplate,
|
||||
string $imapUser,
|
||||
string $imapHost,
|
||||
int $imapPort,
|
||||
string $imapSslMode,
|
||||
string $smtpUser,
|
||||
string $smtpHost,
|
||||
int $smtpPort,
|
||||
string $smtpSslMode): JSONResponse {
|
||||
$this->provisioningManager->newProvisioning(
|
||||
$emailTemplate,
|
||||
$imapUser,
|
||||
$imapHost,
|
||||
$imapPort,
|
||||
$imapSslMode,
|
||||
$smtpUser,
|
||||
$smtpHost,
|
||||
$smtpPort,
|
||||
$smtpSslMode
|
||||
);
|
||||
|
||||
return new JSONResponse(null);
|
||||
}
|
||||
|
||||
public function deprovision(): JSONResponse {
|
||||
$this->provisioningManager->deprovision();
|
||||
|
||||
return new JSONResponse(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -45,7 +45,7 @@ use OCP\AppFramework\Db\Entity;
|
|||
* @method void setInboundSslMode(string $inboundSslMode)
|
||||
* @method string getInboundUser()
|
||||
* @method void setInboundUser(string $inboundUser)
|
||||
* @method string getInboundPassword()
|
||||
* @method string|null getInboundPassword()
|
||||
* @method void setInboundPassword(string $inboundPassword)
|
||||
* @method string getOutboundHost()
|
||||
* @method void setOutboundHost(string $outboundHost)
|
||||
|
@ -55,7 +55,7 @@ use OCP\AppFramework\Db\Entity;
|
|||
* @method void setOutboundSslMode(string $outboundSslMode)
|
||||
* @method string getOutboundUser()
|
||||
* @method void setOutboundUser(string $outboundUser)
|
||||
* @method string getOutboundPassword()
|
||||
* @method string|null getOutboundPassword()
|
||||
* @method void setOutboundPassword(string $outboundPassword)
|
||||
* @method string|null getSignature()
|
||||
* @method void setSignature(string|null $signature)
|
||||
|
@ -63,6 +63,8 @@ use OCP\AppFramework\Db\Entity;
|
|||
* @method void setLastMailboxSync(int $time)
|
||||
* @method string getEditorMode()
|
||||
* @method void setEditorMode(string $editorMode)
|
||||
* @method bool getProvisioned()
|
||||
* @method void setProvisioned(bool $provisioned)
|
||||
*/
|
||||
class MailAccount extends Entity {
|
||||
|
||||
|
@ -82,12 +84,12 @@ class MailAccount extends Entity {
|
|||
protected $signature;
|
||||
protected $lastMailboxSync;
|
||||
protected $editorMode;
|
||||
protected $provisioned;
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*/
|
||||
public function __construct(array $params=[]) {
|
||||
|
||||
if (isset($params['accountId'])) {
|
||||
$this->setId($params['accountId']);
|
||||
}
|
||||
|
@ -131,6 +133,7 @@ class MailAccount extends Entity {
|
|||
}
|
||||
|
||||
$this->addType('lastMailboxSync', 'integer');
|
||||
$this->addType('provisioned', 'bool');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,6 +150,7 @@ class MailAccount extends Entity {
|
|||
'imapSslMode' => $this->getInboundSslMode(),
|
||||
'signature' => $this->getSignature(),
|
||||
'editorMode' => $this->getEditorMode(),
|
||||
'provisioned' => $this->getProvisioned(),
|
||||
];
|
||||
|
||||
if (!is_null($this->getOutboundHost())) {
|
||||
|
|
|
@ -25,8 +25,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace OCA\Mail\Db;
|
||||
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
|
||||
class MailAccountMapper extends QBMapper {
|
||||
|
||||
|
@ -72,6 +76,24 @@ class MailAccountMapper extends QBMapper {
|
|||
return $this->findEntities($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DoesNotExistException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
*/
|
||||
public function findProvisionedAccount(IUser $user): MailAccount {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$query = $qb
|
||||
->select('*')
|
||||
->from($this->getTableName())
|
||||
->where(
|
||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID())),
|
||||
$qb->expr()->eq('provisioned', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
|
||||
);
|
||||
|
||||
return $this->findEntity($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an User Account into the database
|
||||
*
|
||||
|
@ -80,12 +102,20 @@ class MailAccountMapper extends QBMapper {
|
|||
* @return MailAccount
|
||||
*/
|
||||
public function save(MailAccount $account): MailAccount {
|
||||
if (is_null($account->getId())) {
|
||||
if ($account->getId() === null) {
|
||||
return $this->insert($account);
|
||||
} else {
|
||||
$this->update($account);
|
||||
return $account;
|
||||
}
|
||||
|
||||
return $this->update($account);
|
||||
}
|
||||
|
||||
public function deleteProvisionedAccounts(): void {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$delete = $qb->delete($this->getTableName())
|
||||
->where($qb->expr()->eq('provisioned', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)));
|
||||
|
||||
$delete->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Http\Middleware;
|
||||
|
||||
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
|
||||
use OCP\AppFramework\Middleware;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
use OCP\Authentication\Exceptions\PasswordUnavailableException;
|
||||
use OCP\Authentication\LoginCredentials\ICredentials;
|
||||
use OCP\Authentication\LoginCredentials\IStore as ICredentialStore;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class ProvisioningMiddleware extends Middleware {
|
||||
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
/** @var ICredentialStore */
|
||||
private $credentialStore;
|
||||
|
||||
/** @var ProvisioningManager */
|
||||
private $provisioningManager;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
public function __construct(IUserSession $userSession,
|
||||
ICredentialStore $credentialStore,
|
||||
ProvisioningManager $provisioningManager,
|
||||
ILogger $logger) {
|
||||
$this->userSession = $userSession;
|
||||
$this->credentialStore = $credentialStore;
|
||||
$this->provisioningManager = $provisioningManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function beforeController($controller, $methodName) {
|
||||
$user = $this->userSession->getUser();
|
||||
if ($user === null) {
|
||||
// Nothing to update
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$this->provisioningManager->updatePassword(
|
||||
$user,
|
||||
$this->credentialStore->getLoginCredentials()->getPassword()
|
||||
);
|
||||
} catch (CredentialsUnavailableException|PasswordUnavailableException $e) {
|
||||
// Nothing to update
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* Mail
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Migration;
|
||||
|
||||
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\IRepairStep;
|
||||
|
||||
class MigrateProvisioningConfig implements IRepairStep {
|
||||
|
||||
/** @var ProvisioningManager */
|
||||
private $provisioningManager;
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
public function __construct(ProvisioningManager $provisioningManager,
|
||||
IConfig $config) {
|
||||
$this->provisioningManager = $provisioningManager;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Migrate Mail provisioning config from config.php to the database';
|
||||
}
|
||||
|
||||
public function run(IOutput $output) {
|
||||
$fromConfigRaw = $this->config->getSystemValue('app.mail.accounts.default');
|
||||
if ($fromConfigRaw === '') {
|
||||
$output->info("No old config found");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->provisioningManager->getConfig() !== null) {
|
||||
$output->info("Mail provisioning config already set, ignoring old config");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->provisioningManager->importConfig($fromConfigRaw);
|
||||
$this->config->deleteSystemValue('app.mail.accounts.default');
|
||||
$output->info("Config migrated. Accounts not updated yet");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Migration;
|
||||
|
||||
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\IRepairStep;
|
||||
|
||||
class ProvisionAccounts implements IRepairStep {
|
||||
|
||||
/** @var ProvisioningManager */
|
||||
private $provisioningManager;
|
||||
|
||||
public function __construct(ProvisioningManager $provisioningManager) {
|
||||
$this->provisioningManager = $provisioningManager;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return 'Create or update provisioned Mail accounts';
|
||||
}
|
||||
|
||||
public function run(IOutput $output) {
|
||||
$config = $this->provisioningManager->getConfig();
|
||||
if ($config === null) {
|
||||
$output->info("No Mail provisioning config set");
|
||||
return;
|
||||
}
|
||||
|
||||
$cnt = $this->provisioningManager->provision($config);
|
||||
$output->info("$cnt accounts provisioned");
|
||||
}
|
||||
|
||||
}
|
|
@ -54,7 +54,6 @@ class Version0100Date20180825194217 extends SimpleMigrationStep {
|
|||
$table->addColumn('user_id', 'string', [
|
||||
'notnull' => true,
|
||||
'length' => 64,
|
||||
'default' => '',
|
||||
]);
|
||||
$table->addColumn('name', 'string', [
|
||||
'notnull' => false,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use OCP\Migration\IOutput;
|
||||
|
||||
class Version0190Date20191118160843 extends SimpleMigrationStep {
|
||||
|
||||
/**
|
||||
* @param IOutput $output
|
||||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
|
||||
* @param array $options
|
||||
*
|
||||
* @return ISchemaWrapper
|
||||
*/
|
||||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
|
||||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
$accountsTable = $schema->getTable('mail_accounts');
|
||||
$accountsTable->addColumn('provisioned', 'boolean', [
|
||||
'notnull' => true,
|
||||
'default' => false,
|
||||
]);
|
||||
$accountsTable->changeColumn('inbound_password', [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,13 +24,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace OCA\Mail\Service;
|
||||
|
||||
use Exception;
|
||||
use OCA\Mail\Account;
|
||||
use OCA\Mail\Db\MailAccount;
|
||||
use OCA\Mail\Db\MailAccountMapper;
|
||||
use OCA\Mail\Exception\ServiceException;
|
||||
use OCA\Mail\Service\DefaultAccount\Manager;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use function array_map;
|
||||
|
||||
class AccountService {
|
||||
|
||||
|
@ -44,17 +43,12 @@ class AccountService {
|
|||
*/
|
||||
private $accounts;
|
||||
|
||||
/** @var Manager */
|
||||
private $defaultAccountManager;
|
||||
|
||||
/** @var AliasesService */
|
||||
private $aliasesService;
|
||||
|
||||
public function __construct(MailAccountMapper $mapper,
|
||||
Manager $defaultAccountManager,
|
||||
AliasesService $aliasesService) {
|
||||
$this->mapper = $mapper;
|
||||
$this->defaultAccountManager = $defaultAccountManager;
|
||||
$this->aliasesService = $aliasesService;
|
||||
}
|
||||
|
||||
|
@ -64,16 +58,9 @@ class AccountService {
|
|||
*/
|
||||
public function findByUserId(string $currentUserId): array {
|
||||
if ($this->accounts === null) {
|
||||
$accounts = array_map(function ($a) {
|
||||
return $this->accounts = array_map(function ($a) {
|
||||
return new Account($a);
|
||||
}, $this->mapper->findByUserId($currentUserId));
|
||||
|
||||
$defaultAccount = $this->defaultAccountManager->getDefaultAccount();
|
||||
if (!is_null($defaultAccount)) {
|
||||
$accounts[] = new Account($defaultAccount);
|
||||
}
|
||||
|
||||
$this->accounts = $accounts;
|
||||
}, $this->mapper->findByUserId($currentUserId));;
|
||||
}
|
||||
|
||||
return $this->accounts;
|
||||
|
@ -96,13 +83,6 @@ class AccountService {
|
|||
throw new DoesNotExistException("Invalid account id <$accountId>");
|
||||
}
|
||||
|
||||
if ($accountId === Manager::ACCOUNT_ID) {
|
||||
$defaultAccount = $this->defaultAccountManager->getDefaultAccount();
|
||||
if (is_null($defaultAccount)) {
|
||||
throw new DoesNotExistException('Default account config missing');
|
||||
}
|
||||
return new Account($defaultAccount);
|
||||
}
|
||||
return new Account($this->mapper->find($uid, $accountId));
|
||||
}
|
||||
|
||||
|
@ -110,10 +90,6 @@ class AccountService {
|
|||
* @param int $accountId
|
||||
*/
|
||||
public function delete(string $currentUserId, int $accountId): void {
|
||||
if ($accountId === Manager::ACCOUNT_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mailAccount = $this->mapper->find($currentUserId, $accountId);
|
||||
$this->aliasesService->deleteAll($accountId);
|
||||
$this->mapper->delete($mailAccount);
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* Mail
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Service\DefaultAccount;
|
||||
|
||||
use OCA\Mail\Db\MailAccount;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
use OCP\Authentication\LoginCredentials\IStore;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Security\ICrypto;
|
||||
|
||||
class Manager {
|
||||
|
||||
const ACCOUNT_ID = -2;
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
/** @var IStore */
|
||||
private $credentialStore;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
/** @var ICrypto */
|
||||
private $crypto;
|
||||
|
||||
/**
|
||||
* @param IConfig $config
|
||||
* @param IStore $credentialStore
|
||||
* @param ILogger $logger
|
||||
* @param IUserSession $userSession
|
||||
* @param ICrypto $crypto
|
||||
*/
|
||||
public function __construct(IConfig $config,
|
||||
IStore $credentialStore,
|
||||
ILogger $logger,
|
||||
IUserSession $userSession,
|
||||
ICrypto $crypto) {
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
$this->userSession = $userSession;
|
||||
$this->crypto = $crypto;
|
||||
$this->credentialStore = $credentialStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Config|null
|
||||
*/
|
||||
private function getConfig() {
|
||||
$config = $this->config->getSystemValue('app.mail.accounts.default', null);
|
||||
if (is_null($config)) {
|
||||
$this->logger->debug('no default config found');
|
||||
return null;
|
||||
} else {
|
||||
$this->logger->debug('default config to create a default account found');
|
||||
// TODO: check if config is complete
|
||||
return new Config($config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MailAccount|null
|
||||
*/
|
||||
public function getDefaultAccount() {
|
||||
$config = $this->getConfig();
|
||||
if (is_null($config)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$credentials = $this->credentialStore->getLoginCredentials();
|
||||
} catch (CredentialsUnavailableException $ex) {
|
||||
$this->logger->debug('login credentials not available for default account');
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = $this->userSession->getUser();
|
||||
$password = $this->crypto->encrypt($credentials->getPassword());
|
||||
$this->logger->info('building default account for user ' . $user->getUID());
|
||||
|
||||
$account = new MailAccount();
|
||||
$account->setId(self::ACCOUNT_ID);
|
||||
$account->setUserId($user->getUID());
|
||||
$account->setEmail($config->buildEmail($user));
|
||||
$account->setName($user->getDisplayName());
|
||||
|
||||
$account->setInboundUser($config->buildImapUser($user));
|
||||
$account->setInboundHost($config->getImapHost());
|
||||
$account->setInboundPort($config->getImapPort());
|
||||
$account->setInboundSslMode($config->getImapSslMode());
|
||||
$account->setInboundPassword($password);
|
||||
|
||||
$account->setOutboundUser($config->buildSmtpUser($user));
|
||||
$account->setOutboundHost($config->getSmtpHost());
|
||||
$account->setOutboundPort($config->getSmtpPort());
|
||||
$account->setOutboundSslMode($config->getSmtpSslMode());
|
||||
$account->setOutboundPassword($password);
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
}
|
|
@ -21,12 +21,16 @@ declare(strict_types=1);
|
|||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Service\DefaultAccount;
|
||||
namespace OCA\Mail\Service\Provisioning;
|
||||
|
||||
use JsonSerializable;
|
||||
use OCP\IUser;
|
||||
|
||||
class Config {
|
||||
class Config implements JsonSerializable {
|
||||
|
||||
private const VERSION = 1;
|
||||
|
||||
/** @var string[] */
|
||||
private $data;
|
||||
|
||||
/**
|
||||
|
@ -115,13 +119,28 @@ class Config {
|
|||
* @return string
|
||||
*/
|
||||
private function buildUserEmail(string $original, IUser $user) {
|
||||
if (!is_null($user->getUID())) {
|
||||
if ($user->getUID() !== null) {
|
||||
$original = str_replace('%USERID%', $user->getUID(), $original);
|
||||
}
|
||||
if (!is_null($user->getEMailAddress())) {
|
||||
if ($user->getEMailAddress() !== null) {
|
||||
$original = str_replace('%EMAIL%', $user->getEMailAddress(), $original);
|
||||
}
|
||||
return $original;
|
||||
}
|
||||
|
||||
public function setActive(bool $state): self {
|
||||
$this->data['active'] = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function jsonSerialize() {
|
||||
return array_merge(
|
||||
[
|
||||
'active' => false,
|
||||
'version' => self::VERSION,
|
||||
],
|
||||
$this->data
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Service\Provisioning;
|
||||
|
||||
use OCA\Mail\AppInfo\Application;
|
||||
use OCP\IConfig;
|
||||
|
||||
class ConfigMapper {
|
||||
|
||||
private const CONFIG_KEY = 'provisioning_settings';
|
||||
|
||||
/** @var IConfig */
|
||||
private $config;
|
||||
|
||||
public function __construct(IConfig $config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function load(): ?Config {
|
||||
$raw = $this->config->getAppValue(
|
||||
Application::APP_ID,
|
||||
self::CONFIG_KEY
|
||||
);
|
||||
if ($raw === '') {
|
||||
// Not config set yet
|
||||
return null;
|
||||
}
|
||||
return new Config(json_decode($raw, true));
|
||||
}
|
||||
|
||||
public function save(Config $config): Config {
|
||||
$this->config->setAppValue(
|
||||
Application::APP_ID,
|
||||
self::CONFIG_KEY,
|
||||
json_encode($config)
|
||||
);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* Mail
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Service\Provisioning;
|
||||
|
||||
use OCA\Mail\Db\MailAccount;
|
||||
use OCA\Mail\Db\MailAccountMapper;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Security\ICrypto;
|
||||
|
||||
class Manager {
|
||||
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
/** @var ConfigMapper */
|
||||
private $configMapper;
|
||||
|
||||
/** @var MailAccountMapper */
|
||||
private $mailAccountMapper;
|
||||
|
||||
/** @var ICrypto */
|
||||
private $crypto;
|
||||
|
||||
/** @var ILogger */
|
||||
private $logger;
|
||||
|
||||
public function __construct(IUserManager $userManager,
|
||||
ConfigMapper $configMapper,
|
||||
MailAccountMapper $mailAccountMapper,
|
||||
ICrypto $crypto,
|
||||
ILogger $logger) {
|
||||
$this->userManager = $userManager;
|
||||
$this->configMapper = $configMapper;
|
||||
$this->mailAccountMapper = $mailAccountMapper;
|
||||
$this->crypto = $crypto;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getConfig(): ?Config {
|
||||
return $this->configMapper->load();
|
||||
}
|
||||
|
||||
public function provision(Config $config): int {
|
||||
$cnt = 0;
|
||||
$this->userManager->callForAllUsers(function (IUser $user) use ($config, &$cnt) {
|
||||
$this->provisionSingleUser($config, $user);
|
||||
$cnt++;
|
||||
});
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
public function provisionSingleUser(Config $config, IUser $user): void {
|
||||
try {
|
||||
$existing = $this->mailAccountMapper->findProvisionedAccount($user);
|
||||
|
||||
$this->mailAccountMapper->update(
|
||||
$this->updateAccount($user, $existing, $config)
|
||||
);
|
||||
} catch (DoesNotExistException $e) {
|
||||
// Fine, then we create a new one
|
||||
$new = new MailAccount();
|
||||
$new->setUserId($user->getUID());
|
||||
if ($user->getDisplayName() !== $user->getUID()) {
|
||||
// Only set if it's something meaningful
|
||||
$new->setName($user->getDisplayName());
|
||||
}
|
||||
$new->setProvisioned(true);
|
||||
|
||||
$this->mailAccountMapper->insert(
|
||||
$this->updateAccount($user, $new, $config)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function newProvisioning(string $email,
|
||||
string $imapUser,
|
||||
string $imapHost,
|
||||
int $imapPort,
|
||||
string $imapSslMode,
|
||||
string $smtpUser,
|
||||
string $smtpHost,
|
||||
int $smtpPort,
|
||||
string $smtpSslMode): void {
|
||||
$config = $this->configMapper->save(new Config([
|
||||
'active' => true,
|
||||
'email' => $email,
|
||||
'imapUser' => $imapUser,
|
||||
'imapHost' => $imapHost,
|
||||
'imapPort' => $imapPort,
|
||||
'imapSslMode' => $imapSslMode,
|
||||
'smtpUser' => $smtpUser,
|
||||
'smtpHost' => $smtpHost,
|
||||
'smtpPort' => $smtpPort,
|
||||
'smtpSslMode' => $smtpSslMode,
|
||||
]));
|
||||
|
||||
$this->provision($config);
|
||||
}
|
||||
|
||||
private function updateAccount(IUser $user, MailAccount $account, Config $config): MailAccount {
|
||||
$account->setEmail($config->buildEmail($user));
|
||||
$account->setInboundUser($config->buildImapUser($user));
|
||||
$account->setInboundHost($config->getImapHost());
|
||||
$account->setInboundPort($config->getImapPort());
|
||||
$account->setInboundSslMode($config->getImapSslMode());
|
||||
$account->setOutboundUser($config->buildSmtpUser($user));
|
||||
$account->setOutboundHost($config->getSmtpHost());
|
||||
$account->setOutboundPort($config->getSmtpPort());
|
||||
$account->setOutboundSslMode($config->getSmtpSslMode());
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
public function deprovision(): void {
|
||||
$this->mailAccountMapper->deleteProvisionedAccounts();
|
||||
|
||||
$config = $this->configMapper->load();
|
||||
if ($config !== null) {
|
||||
$config->setActive(false);
|
||||
$this->configMapper->save($config);
|
||||
}
|
||||
}
|
||||
|
||||
public function importConfig(array $data): Config {
|
||||
if (!isset($data['imapUser'])) {
|
||||
$data['imapUser'] = $data['email'];
|
||||
}
|
||||
if (!isset($data['smtpUser'])) {
|
||||
$data['smtpUser'] = $data['email'];
|
||||
}
|
||||
|
||||
return $this->configMapper->save(new Config($data));
|
||||
}
|
||||
|
||||
public function updatePassword(IUser $user, string $password): void {
|
||||
try {
|
||||
$account = $this->mailAccountMapper->findProvisionedAccount($user);
|
||||
|
||||
if ($account->getInboundPassword() !== null
|
||||
&& $this->crypto->decrypt($account->getInboundPassword()) === $password
|
||||
&& $account->getOutboundPassword() !== null
|
||||
&& $this->crypto->decrypt($account->getOutboundPassword()) === $password) {
|
||||
$this->logger->debug('Password of provisioned account is up to date');
|
||||
return;
|
||||
}
|
||||
|
||||
$account->setInboundPassword($this->crypto->encrypt($password));
|
||||
$account->setOutboundPassword($this->crypto->encrypt($password));
|
||||
$this->mailAccountMapper->update($account);
|
||||
|
||||
$this->logger->debug('Provisioned account password udpated');
|
||||
} catch (DoesNotExistException $e) {
|
||||
// Nothing to update
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Settings;
|
||||
|
||||
use OCA\Mail\AppInfo\Application;
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\Settings\ISettings;
|
||||
|
||||
class AdminSettings implements ISettings {
|
||||
|
||||
/** @var IInitialStateService */
|
||||
private $initialStateService;
|
||||
|
||||
/** @var ProvisioningManager */
|
||||
private $provisioningManager;
|
||||
|
||||
public function __construct(IInitialStateService $initialStateService,
|
||||
ProvisioningManager $provisioningManager) {
|
||||
$this->initialStateService = $initialStateService;
|
||||
$this->provisioningManager = $provisioningManager;
|
||||
}
|
||||
|
||||
public function getForm() {
|
||||
$this->initialStateService->provideInitialState(
|
||||
Application::APP_ID,
|
||||
'provisioning_settings',
|
||||
$this->provisioningManager->getConfig() ?? new Config([
|
||||
'active' => false,
|
||||
'email' => '%USERID%@domain.com',
|
||||
'imapUser' => '%USERID%@domain.com',
|
||||
'imapHost' => 'imap.domain.com',
|
||||
'imapPort' => 993,
|
||||
'imapSslMode' => 'ssl',
|
||||
'smtpUser' => '%USERID%@domain.com',
|
||||
'smtpHost' => 'smtp.domain.com',
|
||||
'smtpPort' => 587,
|
||||
'smtpSslMode' => 'tls',
|
||||
])
|
||||
);
|
||||
|
||||
return new TemplateResponse(Application::APP_ID, 'settings-admin');
|
||||
}
|
||||
|
||||
public function getSection() {
|
||||
return 'groupware';
|
||||
}
|
||||
|
||||
public function getPriority() {
|
||||
return 90;
|
||||
}
|
||||
|
||||
}
|
|
@ -37,7 +37,7 @@
|
|||
<ActionRouter :to="settingsRoute" icon="icon-settings">
|
||||
{{ t('mail', 'Edit account') }}
|
||||
</ActionRouter>
|
||||
<ActionButton icon="icon-delete" @click="deleteAccount">
|
||||
<ActionButton v-if="!account.provisioned" icon="icon-delete" @click="deleteAccount">
|
||||
{{ t('mail', 'Delete account') }}
|
||||
</ActionButton>
|
||||
<ActionInput icon="icon-add" @submit="createFolder">
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<!--
|
||||
- @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div id="mail-admin-settings" class="section">
|
||||
<h2>{{ t('mail', 'Mail app') }}</h2>
|
||||
<h3>{{ t('mail', 'The mail app allows users to read mails on their IMAP accounts.') }}</h3>
|
||||
<h3>
|
||||
{{
|
||||
t(
|
||||
'mail',
|
||||
'Here you can find instance-wide settings. User specific settings are found in the app itself (bottom-left corner).'
|
||||
)
|
||||
}}
|
||||
</h3>
|
||||
<ProvisioningSettings :settings="provisioningSettings" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProvisioningSettings from './ProvisioningSettings'
|
||||
|
||||
export default {
|
||||
name: 'AdminSettings',
|
||||
components: {
|
||||
ProvisioningSettings,
|
||||
},
|
||||
props: {
|
||||
provisioningSettings: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,99 @@
|
|||
<!--
|
||||
- @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="provision-preview">
|
||||
<b>
|
||||
<span v-if="data.uid">uid={{ data.uid }}</span>
|
||||
<span v-if="data.email">email={{ email }}</span>
|
||||
</b>
|
||||
<br />
|
||||
{{ t('mail', 'Email: {email}', {email}) }}<br />
|
||||
{{
|
||||
t('mail', 'IMAP: {user} on {host}:{port} ({ssl} encryption)', {
|
||||
user: imapUser,
|
||||
host: imapHost,
|
||||
port: imapPort,
|
||||
ssl: imapSslMode,
|
||||
})
|
||||
}}<br />
|
||||
{{
|
||||
t('mail', 'SMTP: {user} on {host}:{port} ({ssl} encryption)', {
|
||||
user: smtpUser,
|
||||
host: smtpHost,
|
||||
port: smtpPort,
|
||||
ssl: smtpSslMode,
|
||||
})
|
||||
}}<br />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProvisionPreview',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
templates: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
email() {
|
||||
return this.templates.email.replace('%USERID%', this.data.uid).replace('%EMAIL%', this.data.email)
|
||||
},
|
||||
imapHost() {
|
||||
return this.templates.imapHost
|
||||
},
|
||||
imapPort() {
|
||||
return this.templates.imapPort
|
||||
},
|
||||
imapSslMode() {
|
||||
return this.templates.imapSslMode
|
||||
},
|
||||
imapUser() {
|
||||
return this.templates.imapUser.replace('%USERID%', this.data.uid).replace('%EMAIL%', this.data.email)
|
||||
},
|
||||
smtpHost() {
|
||||
return this.templates.smtpHost
|
||||
},
|
||||
smtpPort() {
|
||||
return this.templates.smtpPort
|
||||
},
|
||||
smtpSslMode() {
|
||||
return this.templates.smtpSslMode
|
||||
},
|
||||
smtpUser() {
|
||||
return this.templates.smtpUser.replace('%USERID%', this.data.uid).replace('%EMAIL%', this.data.email)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.provision-preview {
|
||||
border: 1px solid var(--color-border-dark);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,428 @@
|
|||
<!--
|
||||
- @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3>Account provisioning</h3>
|
||||
<p>
|
||||
{{
|
||||
t(
|
||||
'mail',
|
||||
'You can configure a template for account settings, from which all users will get an account provisioned from.'
|
||||
)
|
||||
}}
|
||||
{{
|
||||
t(
|
||||
'mail',
|
||||
"This setting only makes most sense if you use the same user back-end for your organization's Nextcloud and mail server."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<div>
|
||||
<input id="mail-provision-toggle" v-model="active" type="checkbox" class="checkbox" />
|
||||
<label for="mail-provision-toggle">
|
||||
{{ t('mail', 'Provision an account for every user') }}
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="active" class="form-preview-row">
|
||||
<form @submit.prevent="submit">
|
||||
<div class="settings-group">
|
||||
<div class="group-title">{{ t('mail', 'General') }}</div>
|
||||
<div class="group-inputs">
|
||||
<label for="mail-provision-email"> {{ t('mail', 'Email address') }}* </label>
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-email"
|
||||
v-model="emailTemplate"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<div class="group-title">{{ t('mail', 'IMAP') }}</div>
|
||||
<div class="group-inputs">
|
||||
<label for="mail-provision-imap-user">
|
||||
{{ t('mail', 'User') }}*
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-imap-user"
|
||||
v-model="imapUser"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="text"
|
||||
/>
|
||||
</label>
|
||||
<div class="flex-row">
|
||||
<label for="mail-provision-imap-host">
|
||||
{{ t('mail', 'Host') }}
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-imap-host"
|
||||
v-model="imapHost"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="text"
|
||||
/>
|
||||
</label>
|
||||
<label for="mail-provision-imap-port">
|
||||
{{ t('mail', 'Port') }}
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-imap-port"
|
||||
v-model="imapPort"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="number"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<input
|
||||
id="mail-provision-imap-user-none"
|
||||
v-model="imapSslMode"
|
||||
type="radio"
|
||||
name="man-imap-sec"
|
||||
:disabled="loading"
|
||||
value="none"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-imap-user-none"
|
||||
:class="{primary: imapSslMode === 'none'}"
|
||||
>{{ t('mail', 'None') }}</label
|
||||
>
|
||||
<input
|
||||
id="mail-provision-imap-user-ssl"
|
||||
v-model="imapSslMode"
|
||||
type="radio"
|
||||
name="man-imap-sec"
|
||||
:disabled="loading"
|
||||
value="ssl"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-imap-user-ssl"
|
||||
:class="{primary: imapSslMode === 'ssl'}"
|
||||
>{{ t('mail', 'SSL/TLS') }}</label
|
||||
>
|
||||
<input
|
||||
id="mail-provision-imap-user-tls"
|
||||
v-model="imapSslMode"
|
||||
type="radio"
|
||||
name="man-imap-sec"
|
||||
:disabled="loading"
|
||||
value="tls"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-imap-user-tls"
|
||||
:class="{primary: imapSslMode === 'tls'}"
|
||||
>{{ t('mail', 'STARTTLS') }}</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<div class="group-title">{{ t('mail', 'SMTP') }}</div>
|
||||
<div class="group-inputs">
|
||||
<label for="mail-provision-smtp-user">
|
||||
{{ t('mail', 'User') }}*
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-smtp-user"
|
||||
v-model="smtpUser"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="text"
|
||||
/>
|
||||
</label>
|
||||
<div class="flex-row">
|
||||
<label for="mail-provision-imap-host">
|
||||
{{ t('mail', 'Host') }}
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-smtp-host"
|
||||
v-model="smtpHost"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="text"
|
||||
/>
|
||||
</label>
|
||||
<label for="mail-provision-smtp-port">
|
||||
{{ t('mail', 'Port') }}
|
||||
<br />
|
||||
<input
|
||||
id="mail-provision-smtp-port"
|
||||
v-model="smtpPort"
|
||||
:disabled="loading"
|
||||
name="email"
|
||||
type="number"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<input
|
||||
id="mail-provision-smtp-user-none"
|
||||
v-model="smtpSslMode"
|
||||
type="radio"
|
||||
name="man-smtp-sec"
|
||||
:disabled="loading"
|
||||
value="none"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-smtp-user-none"
|
||||
:class="{primary: smtpSslMode === 'none'}"
|
||||
>{{ t('mail', 'None') }}</label
|
||||
>
|
||||
<input
|
||||
id="mail-provision-smtp-user-ssl"
|
||||
v-model="smtpSslMode"
|
||||
type="radio"
|
||||
name="man-smtp-sec"
|
||||
:disabled="loading"
|
||||
value="ssl"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-smtp-user-ssl"
|
||||
:class="{primary: smtpSslMode === 'ssl'}"
|
||||
>{{ t('mail', 'SSL/TLS') }}</label
|
||||
>
|
||||
<input
|
||||
id="mail-provision-smtp-user-tls"
|
||||
v-model="smtpSslMode"
|
||||
type="radio"
|
||||
name="man-smtp-sec"
|
||||
:disabled="loading"
|
||||
value="tls"
|
||||
/>
|
||||
<label
|
||||
class="button"
|
||||
for="mail-provision-smtp-user-tls"
|
||||
:class="{primary: smtpSslMode === 'tls'}"
|
||||
>{{ t('mail', 'STARTTLS') }}</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<div class="group-title"></div>
|
||||
<div class="group-inputs">
|
||||
<input
|
||||
type="submit"
|
||||
class="primary"
|
||||
:disabled="loading"
|
||||
:value="t('mail', 'Apply and create/update for all users')"
|
||||
/>
|
||||
<input
|
||||
type="button"
|
||||
:disabled="loading"
|
||||
:value="t('mail', 'Disable and un-provision existing accounts')"
|
||||
@click="disable"
|
||||
/>
|
||||
<br />
|
||||
<small>{{
|
||||
t('mail', "* %USERID% and %EMAIL% will be replaced with the user's UID and email")
|
||||
}}</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<h4>Preview</h4>
|
||||
<p>
|
||||
{{
|
||||
t('mail', 'With the settings above, the app will create account settings in the following way:')
|
||||
}}
|
||||
</p>
|
||||
<div class="previews">
|
||||
<ProvisionPreview class="preview-item" :templates="previewTemplates" :data="previewData1" />
|
||||
<ProvisionPreview class="preview-item" :templates="previewTemplates" :data="previewData2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import logger from '../../logger'
|
||||
import ProvisionPreview from './ProvisionPreview'
|
||||
import {disableProvisioning, saveProvisioningSettings} from '../../service/SettingsService'
|
||||
|
||||
export default {
|
||||
name: 'ProvisioningSettings',
|
||||
components: {ProvisionPreview},
|
||||
props: {
|
||||
settings: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: !!this.settings.active,
|
||||
emailTemplate: this.settings.email || '',
|
||||
imapHost: this.settings.imapHost || 'mx.domain.com',
|
||||
imapPort: this.settings.imapPort || 993,
|
||||
imapUser: this.settings.imapUser || '%USERID%domain.com',
|
||||
imapSslMode: this.settings.imapSslMode || 'ssl',
|
||||
smtpHost: this.settings.smtpHost || 'mx.domain.com',
|
||||
smtpPort: this.settings.smtpPort || 587,
|
||||
smtpUser: this.settings.smtpUser || '%USERID%domain.com',
|
||||
smtpSslMode: this.settings.smtpSslMode || 'tls',
|
||||
previewData1: {
|
||||
uid: 'user123',
|
||||
email: '',
|
||||
},
|
||||
previewData2: {
|
||||
uid: 'user321',
|
||||
email: 'user@domain.com',
|
||||
},
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
previewTemplates() {
|
||||
return {
|
||||
email: this.emailTemplate,
|
||||
imapUser: this.imapUser,
|
||||
imapHost: this.imapHost,
|
||||
imapPort: this.imapPort,
|
||||
imapSslMode: this.imapSslMode,
|
||||
smtpUser: this.smtpUser,
|
||||
smtpHost: this.smtpHost,
|
||||
smtpPort: this.smtpPort,
|
||||
smtpSslMode: this.smtpSslMode,
|
||||
}
|
||||
},
|
||||
},
|
||||
beforeMount() {
|
||||
logger.debug('provisioning settings loaded', {settings: this.settings})
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.loading = true
|
||||
|
||||
return saveProvisioningSettings({
|
||||
emailTemplate: this.emailTemplate,
|
||||
imapUser: this.imapUser,
|
||||
imapHost: this.imapHost,
|
||||
imapPort: this.imapPort,
|
||||
imapSslMode: this.imapSslMode,
|
||||
smtpUser: this.smtpUser,
|
||||
smtpHost: this.smtpHost,
|
||||
smtpPort: this.smtpPort,
|
||||
smtpSslMode: this.smtpSslMode,
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('provisioning settings updated')
|
||||
})
|
||||
.catch(error => {
|
||||
// TODO: show user feedback
|
||||
logger.error('Could not save provisioning settings', {error})
|
||||
})
|
||||
.then(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
disable() {
|
||||
this.loading = true
|
||||
|
||||
return disableProvisioning()
|
||||
.then(() => {
|
||||
logger.info('deprovisioned successfully')
|
||||
})
|
||||
.catch(error => {
|
||||
logger.error('could not deprovision accounts', {error})
|
||||
})
|
||||
.then(() => {
|
||||
this.active = false
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-preview-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
div:last-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.group-title {
|
||||
min-width: 100px;
|
||||
text-align: right;
|
||||
margin: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.group-inputs {
|
||||
margin: 10px;
|
||||
flex-grow: 1;
|
||||
|
||||
input[type='text'] {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.previews {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -10px;
|
||||
|
||||
.preview-item {
|
||||
flex-grow: 1;
|
||||
margin: 10px;
|
||||
padding: 25px;
|
||||
}
|
||||
}
|
||||
input[type='radio'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
form {
|
||||
label {
|
||||
color: var(--color-text-maxcontrast);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {generateFilePath} from '@nextcloud/router'
|
||||
import {getRequestToken} from '@nextcloud/auth'
|
||||
import {loadState} from '@nextcloud/initial-state'
|
||||
import Vue from 'vue'
|
||||
|
||||
import AdminSettings from './components/settings/AdminSettings'
|
||||
import Nextcloud from './mixins/Nextcloud'
|
||||
|
||||
__webpack_nonce__ = btoa(getRequestToken())
|
||||
__webpack_public_path__ = generateFilePath('mail', '', 'js/')
|
||||
|
||||
Vue.mixin(Nextcloud)
|
||||
|
||||
const View = Vue.extend(AdminSettings)
|
||||
new View({
|
||||
propsData: {
|
||||
provisioningSettings: loadState('mail', 'provisioning_settings') || {},
|
||||
},
|
||||
}).$mount('#mail-admin-settings')
|
15
src/main.js
15
src/main.js
|
@ -21,16 +21,16 @@
|
|||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import {getRequestToken} from '@nextcloud/auth'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import {sync} from 'vuex-router-sync'
|
||||
import {translate, translatePlural} from '@nextcloud/l10n'
|
||||
import {generateFilePath} from '@nextcloud/router'
|
||||
import VueShortKey from 'vue-shortkey'
|
||||
import VTooltip from 'v-tooltip'
|
||||
|
||||
import App from './App'
|
||||
import Nextcloud from './mixins/Nextcloud'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import {fixAccountId} from './service/AccountService'
|
||||
|
||||
__webpack_nonce__ = btoa(getRequestToken())
|
||||
|
@ -38,12 +38,7 @@ __webpack_public_path__ = generateFilePath('mail', '', 'js/')
|
|||
|
||||
sync(store, router)
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
t: translate,
|
||||
n: translatePlural,
|
||||
},
|
||||
})
|
||||
Vue.mixin(Nextcloud)
|
||||
|
||||
Vue.use(VueShortKey, {prevent: ['input', 'div']})
|
||||
Vue.use(VTooltip)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {translate as t, translatePlural as n} from '@nextcloud/l10n'
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
t,
|
||||
n,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import {generateUrl} from '@nextcloud/router'
|
||||
|
||||
export const saveProvisioningSettings = config => {
|
||||
const url = generateUrl('/apps/mail/api/settings/provisioning')
|
||||
|
||||
return axios.post(url, config).then(resp => resp.data)
|
||||
}
|
||||
|
||||
export const disableProvisioning = () => {
|
||||
const url = generateUrl('/apps/mail/api/settings/provisioning')
|
||||
|
||||
return axios.delete(url).then(resp => resp.data)
|
||||
}
|
|
@ -6,12 +6,17 @@
|
|||
<h2>{{ t('mail', 'Account settings') }}</h2>
|
||||
<p>
|
||||
<strong>{{ displayName }}</strong> <{{ email }}>
|
||||
<a class="button icon-rename" href="#account-form" :title="t('mail', 'Change name')"></a>
|
||||
<a
|
||||
v-if="!account.provisioned"
|
||||
class="button icon-rename"
|
||||
href="#account-form"
|
||||
:title="t('mail', 'Change name')"
|
||||
></a>
|
||||
</p>
|
||||
</div>
|
||||
<SignatureSettings :account="account" />
|
||||
<EditorSettings :account="account" />
|
||||
<div class="section">
|
||||
<div v-if="!account.provisioned" class="section">
|
||||
<h2>{{ t('mail', 'Mail server') }}</h2>
|
||||
<div id="mail-settings">
|
||||
<AccountForm
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
script(\OCA\Mail\AppInfo\Application::APP_ID, 'settings');
|
||||
|
||||
?>
|
||||
<div id="mail-admin-settings">
|
||||
</div>
|
|
@ -64,12 +64,14 @@ class MailTransmissionIntegrationTest extends TestCase {
|
|||
parent::setUp();
|
||||
|
||||
$this->resetImapAccount();
|
||||
$this->user = $this->createTestUser();
|
||||
|
||||
/** @var ICrypto $crypo */
|
||||
$crypo = OC::$server->getCrypto();
|
||||
/** @var MailAccountMapper $mapper */
|
||||
$mapper = OC::$server->query(MailAccountMapper::class);
|
||||
$mailAccount = MailAccount::fromParams([
|
||||
'userId' => $this->user->getUID(),
|
||||
'email' => 'user@domain.tld',
|
||||
'inboundHost' => 'localhost',
|
||||
'inboundPort' => '993',
|
||||
|
@ -86,7 +88,6 @@ class MailTransmissionIntegrationTest extends TestCase {
|
|||
|
||||
$this->account = new Account($mailAccount);
|
||||
$this->attachmentService = OC::$server->query(IAttachmentService::class);
|
||||
$this->user = $this->createTestUser();
|
||||
$userFolder = OC::$server->getUserFolder($this->user->getUID());
|
||||
$this->transmission = new MailTransmission(
|
||||
$userFolder,
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Controller;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
|
||||
use OCA\Mail\Controller\SettingsController;
|
||||
use OCA\Mail\Tests\Integration\TestCase;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
|
||||
class SettingsControllerTest extends TestCase {
|
||||
|
||||
/** @var ServiceMockObject */
|
||||
private $mock;
|
||||
|
||||
/** @var SettingsController */
|
||||
private $controller;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->mock = $this->createServiceMock(SettingsController::class);
|
||||
$this->controller = $this->mock->getService();
|
||||
}
|
||||
|
||||
public function testProvisioning() {
|
||||
$this->mock->getParameter('provisioningManager')
|
||||
->expects($this->once())
|
||||
->method('newProvisioning')
|
||||
->with(
|
||||
'%USERID%@domain.com',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
993,
|
||||
'ssl',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
567,
|
||||
'tls'
|
||||
);
|
||||
|
||||
$response = $this->controller->provisioning(
|
||||
'%USERID%@domain.com',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
993,
|
||||
'ssl',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
567,
|
||||
'tls'
|
||||
);
|
||||
|
||||
$this->assertInstanceOf(JSONResponse::class, $response);
|
||||
}
|
||||
|
||||
public function testDeprovision() {
|
||||
$this->mock->getParameter('provisioningManager')
|
||||
->expects($this->once())
|
||||
->method('deprovision');
|
||||
|
||||
$response = $this->controller->deprovision();
|
||||
|
||||
$this->assertInstanceOf(JSONResponse::class, $response);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ class MailAccountTest extends TestCase {
|
|||
$a->setOutboundPassword('xxxx');
|
||||
$a->setOutboundSslMode('ssl');
|
||||
$a->setEditorMode('html');
|
||||
$a->setProvisioned(false);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'accountId' => 12345,
|
||||
|
@ -57,6 +58,7 @@ class MailAccountTest extends TestCase {
|
|||
'smtpSslMode' => 'ssl',
|
||||
'signature' => null,
|
||||
'editorMode' => 'html',
|
||||
'provisioned' => false,
|
||||
), $a->toJson());
|
||||
}
|
||||
|
||||
|
@ -75,6 +77,7 @@ class MailAccountTest extends TestCase {
|
|||
'smtpSslMode' => 'ssl',
|
||||
'signature' => null,
|
||||
'editorMode' => null,
|
||||
'provisioned' => false,
|
||||
];
|
||||
$a = new MailAccount($expected);
|
||||
// TODO: fix inconsistency
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Http\Middleware;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Controller\PageController;
|
||||
use OCA\Mail\Http\Middleware\ProvisioningMiddleware;
|
||||
use OCA\Mail\Service\Provisioning\Manager;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
use OCP\Authentication\Exceptions\PasswordUnavailableException;
|
||||
use OCP\Authentication\LoginCredentials\ICredentials;
|
||||
use OCP\Authentication\LoginCredentials\IStore;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ProvisioningMiddlewareTest extends TestCase {
|
||||
|
||||
/** @var IUserSession|MockObject */
|
||||
private $userSession;
|
||||
|
||||
/** @var IStore|MockObject */
|
||||
private $credentialStore;
|
||||
|
||||
/** @var Manager|MockObject */
|
||||
private $provisioningManager;
|
||||
|
||||
/** @var ILogger|MockObject */
|
||||
private $logger;
|
||||
|
||||
/** @var ProvisioningMiddleware */
|
||||
private $middleware;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->userSession = $this->createMock(IUserSession::class);
|
||||
$this->credentialStore = $this->createMock(IStore::class);
|
||||
$this->provisioningManager = $this->createMock(Manager::class);
|
||||
$this->logger = $this->createMock(ILogger::class);
|
||||
|
||||
$this->middleware = new ProvisioningMiddleware(
|
||||
$this->userSession,
|
||||
$this->credentialStore,
|
||||
$this->provisioningManager,
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
||||
public function testBeforeControllerNotLoggedIn() {
|
||||
$this->credentialStore->expects($this->never())
|
||||
->method('getLoginCredentials');
|
||||
$this->provisioningManager->expects($this->never())
|
||||
->method('updatePassword');
|
||||
|
||||
$this->middleware->beforeController(
|
||||
$this->createMock(PageController::class),
|
||||
'index'
|
||||
);
|
||||
}
|
||||
|
||||
public function testBeforeControllerNoCredentialsAvailable() {
|
||||
$user = $this->createMock(IUser::class);
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
$this->credentialStore->expects($this->once())
|
||||
->method('getLoginCredentials')
|
||||
->willThrowException($this->createMock(CredentialsUnavailableException::class));
|
||||
$this->provisioningManager->expects($this->never())
|
||||
->method('updatePassword');
|
||||
|
||||
$this->middleware->beforeController(
|
||||
$this->createMock(PageController::class),
|
||||
'index'
|
||||
);
|
||||
}
|
||||
|
||||
public function testBeforeControllerNoPasswordAvailable() {
|
||||
$user = $this->createMock(IUser::class);
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
$credentials = $this->createMock(ICredentials::class);
|
||||
$this->credentialStore->expects($this->once())
|
||||
->method('getLoginCredentials')
|
||||
->willReturn($credentials);
|
||||
$credentials->expects($this->once())
|
||||
->method('getPassword')
|
||||
->willThrowException($this->createMock(PasswordUnavailableException::class));
|
||||
$this->provisioningManager->expects($this->never())
|
||||
->method('updatePassword');
|
||||
|
||||
$this->middleware->beforeController(
|
||||
$this->createMock(PageController::class),
|
||||
'index'
|
||||
);
|
||||
}
|
||||
|
||||
public function testBeforeController() {
|
||||
$user = $this->createMock(IUser::class);
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
$credentials = $this->createMock(ICredentials::class);
|
||||
$this->credentialStore->expects($this->once())
|
||||
->method('getLoginCredentials')
|
||||
->willReturn($credentials);
|
||||
$credentials->expects($this->once())
|
||||
->method('getPassword')
|
||||
->willReturn('123456');
|
||||
$this->provisioningManager->expects($this->once())
|
||||
->method('updatePassword')
|
||||
->with(
|
||||
$user,
|
||||
'123456'
|
||||
);
|
||||
|
||||
$this->middleware->beforeController(
|
||||
$this->createMock(PageController::class),
|
||||
'index'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Migration;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Migration\MigrateProvisioningConfig;
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
use OCP\Migration\IOutput;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class MigrateProvisioningConfigTest extends TestCase {
|
||||
|
||||
/** @var ServiceMockObject */
|
||||
private $mock;
|
||||
|
||||
/** @var MigrateProvisioningConfig */
|
||||
private $repairStep;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->mock = $this->createServiceMock(MigrateProvisioningConfig::class);
|
||||
$this->repairStep = $this->mock->getService();
|
||||
}
|
||||
|
||||
|
||||
public function testRunNoConfigToMigrate() {
|
||||
/** @var IOutput|MockObject $output */
|
||||
$output = $this->createMock(IOutput::class);
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with('app.mail.accounts.default')
|
||||
->willReturn('');
|
||||
|
||||
$this->repairStep->run($output);
|
||||
}
|
||||
|
||||
public function testRunAlreadyMigrated() {
|
||||
/** @var IOutput|MockObject $output */
|
||||
$output = $this->createMock(IOutput::class);
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with('app.mail.accounts.default')
|
||||
->willReturn([]);
|
||||
$this->mock->getParameter('provisioningManager')
|
||||
->expects($this->once())
|
||||
->method('getConfig')
|
||||
->willReturn($this->createMock(Config::class));
|
||||
|
||||
$this->repairStep->run($output);
|
||||
}
|
||||
|
||||
public function testRun() {
|
||||
/** @var IOutput|MockObject $output */
|
||||
$output = $this->createMock(IOutput::class);
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with('app.mail.accounts.default')
|
||||
->willReturn([]);
|
||||
$this->mock->getParameter('provisioningManager')
|
||||
->expects($this->once())
|
||||
->method('getConfig')
|
||||
->willReturn(null);
|
||||
$this->mock->getParameter('provisioningManager')
|
||||
->expects($this->once())
|
||||
->method('importConfig');
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('deleteSystemValue')
|
||||
->with('app.mail.accounts.default');
|
||||
|
||||
$this->repairStep->run($output);
|
||||
}
|
||||
|
||||
public function testGetName() {
|
||||
$name = $this->repairStep->getName();
|
||||
|
||||
$this->assertEquals('Migrate Mail provisioning config from config.php to the database', $name);
|
||||
}
|
||||
|
||||
}
|
|
@ -27,44 +27,42 @@ use OCA\Mail\Db\MailAccount;
|
|||
use OCA\Mail\Db\MailAccountMapper;
|
||||
use OCA\Mail\Service\AccountService;
|
||||
use OCA\Mail\Service\AliasesService;
|
||||
use OCA\Mail\Service\DefaultAccount\Manager;
|
||||
use OCP\IL10N;
|
||||
use PHPUnit_Framework_MockObject_MockObject;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class AccountServiceTest extends TestCase {
|
||||
|
||||
/** @var string */
|
||||
private $user = 'herbert';
|
||||
|
||||
/** @var MailAccountMapper|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var MailAccountMapper|MockObject */
|
||||
private $mapper;
|
||||
|
||||
/** @var IL10N|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var IL10N|MockObject */
|
||||
private $l10n;
|
||||
|
||||
/** @var AccountService|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var AccountService|MockObject */
|
||||
private $accountService;
|
||||
|
||||
/** @var AliasesService|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var AliasesService|MockObject */
|
||||
private $aliasesService;
|
||||
|
||||
/** @var MailAccount|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var MailAccount|MockObject */
|
||||
private $account1;
|
||||
|
||||
/** @var MailAccount|PHPUnit_Framework_MockObject_MockObject */
|
||||
/** @var MailAccount|MockObject */
|
||||
private $account2;
|
||||
|
||||
/** @var Manager|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $defaultAccountManager;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->mapper = $this->createMock(MailAccountMapper::class);
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
$this->defaultAccountManager = $this->createMock(Manager::class);
|
||||
$this->aliasesService = $this->createMock(AliasesService::class);
|
||||
$this->accountService = new AccountService($this->mapper, $this->defaultAccountManager, $this->aliasesService);
|
||||
$this->accountService = new AccountService(
|
||||
$this->mapper,
|
||||
$this->aliasesService
|
||||
);
|
||||
|
||||
$this->account1 = $this->createMock(MailAccount::class);
|
||||
$this->account2 = $this->createMock(MailAccount::class);
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* Mail
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Service\DefaultAccount;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Db\MailAccount;
|
||||
use OCA\Mail\Service\DefaultAccount\Manager;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
use OCP\Authentication\LoginCredentials\ICredentials;
|
||||
use OCP\Authentication\LoginCredentials\IStore;
|
||||
use OCP\IConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Security\ICrypto;
|
||||
use PHPUnit_Framework_MockObject_MockObject;
|
||||
|
||||
class ManagerTest extends TestCase {
|
||||
|
||||
/** @var IConfig|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $config;
|
||||
|
||||
/** @var IStore|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $credentialStore;
|
||||
|
||||
/** @var ILogger|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $logger;
|
||||
|
||||
/** @var IUserSession|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $userSession;
|
||||
|
||||
/** @var ICrypto|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $crypto;
|
||||
|
||||
/** @var Manager|PHPUnit_Framework_MockObject_MockObject */
|
||||
private $manager;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->credentialStore = $this->createMock(IStore::class);
|
||||
$this->logger = $this->createMock(ILogger::class);
|
||||
$this->userSession = $this->createMock(IUserSession::class);
|
||||
$this->crypto = $this->createMock(ICrypto::class);
|
||||
|
||||
$this->manager = new Manager($this->config, $this->credentialStore, $this->logger, $this->userSession, $this->crypto);
|
||||
}
|
||||
|
||||
public function testGetDefaultAccountWithoutConfigAvailble() {
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with($this->equalTo('app.mail.accounts.default'), $this->equalTo(null))
|
||||
->willReturn(null);
|
||||
|
||||
$account = $this->manager->getDefaultAccount();
|
||||
|
||||
$this->assertSame(null, $account);
|
||||
}
|
||||
|
||||
public function testGetDefaultAccountWithCredentialsUnavailable() {
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with($this->equalTo('app.mail.accounts.default'), $this->equalTo(null))
|
||||
->willReturn([
|
||||
'email' => '%EMAIL%',
|
||||
]);
|
||||
$this->credentialStore->expects($this->once())
|
||||
->method('getLoginCredentials')
|
||||
->willThrowException(new CredentialsUnavailableException());
|
||||
|
||||
$account = $this->manager->getDefaultAccount();
|
||||
|
||||
$this->assertSame(null, $account);
|
||||
}
|
||||
|
||||
public function testGetDefaultAccount() {
|
||||
$this->config->expects($this->once())
|
||||
->method('getSystemValue')
|
||||
->with($this->equalTo('app.mail.accounts.default'), $this->equalTo(null))
|
||||
->willReturn([
|
||||
'email' => '%EMAIL%',
|
||||
'imapHost' => 'imap.domain.tld',
|
||||
'imapPort' => 993,
|
||||
'imapSslMode' => 'ssl',
|
||||
'smtpHost' => 'smtp.domain.tld',
|
||||
'smtpPort' => 465,
|
||||
'smtpSslMode' => 'tls',
|
||||
]);
|
||||
$credentials = $this->createMock(ICredentials::class);
|
||||
$user = $this->createMock(IUser::class);
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
$this->credentialStore->expects($this->once())
|
||||
->method('getLoginCredentials')
|
||||
->willReturn($credentials);
|
||||
$credentials->expects($this->once())
|
||||
->method('getPassword')
|
||||
->willReturn('123456');
|
||||
$this->crypto->expects($this->once())
|
||||
->method('encrypt')
|
||||
->with($this->equalTo('123456'))
|
||||
->willReturn('encrypted');
|
||||
$expected = new MailAccount();
|
||||
$expected->setId(Manager::ACCOUNT_ID);
|
||||
$user->expects($this->any())
|
||||
->method('getUID')
|
||||
->willReturn('user123');
|
||||
$user->expects($this->any())
|
||||
->method('getEMailAddress')
|
||||
->willReturn('user@domain.tld');
|
||||
$user->expects($this->once())
|
||||
->method('getDisplayName')
|
||||
->willReturn('Test User');
|
||||
$expected->setUserId('user123');
|
||||
$expected->setEmail('user@domain.tld');
|
||||
$expected->setName('Test User');
|
||||
$expected->setInboundUser('user@domain.tld');
|
||||
$expected->setInboundHost('imap.domain.tld');
|
||||
$expected->setInboundPort(993);
|
||||
$expected->setInboundSslMode('ssl');
|
||||
$expected->setInboundPassword('encrypted');
|
||||
$expected->setOutboundUser('user@domain.tld');
|
||||
$expected->setOutboundHost('smtp.domain.tld');
|
||||
$expected->setOutboundPort(465);
|
||||
$expected->setOutboundSslMode('tls');
|
||||
$expected->setOutboundPassword('encrypted');
|
||||
|
||||
$account = $this->manager->getDefaultAccount();
|
||||
|
||||
$this->assertEquals($expected, $account);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Service\Provisioning;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
use OCA\Mail\Service\Provisioning\ConfigMapper;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ConfigMapperTest extends TestCase {
|
||||
|
||||
/** @var ServiceMockObject */
|
||||
private $mock;
|
||||
|
||||
/** @var ConfigMapper */
|
||||
private $mapper;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->mock = $this->createServiceMock(ConfigMapper::class);
|
||||
$this->mapper = $this->mock->getService();
|
||||
}
|
||||
|
||||
public function testSave() {
|
||||
/** @var Config|MockObject $config */
|
||||
$config = $this->createMock(Config::class);
|
||||
$config->expects($this->once())
|
||||
->method('jsonSerialize')
|
||||
->willReturn([]);
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('setAppValue')
|
||||
->with('mail', 'provisioning_settings', '[]');
|
||||
|
||||
$this->mapper->save($config);
|
||||
}
|
||||
|
||||
public function testLoadNoConfig() {
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('mail', 'provisioning_settings')
|
||||
->willReturn('');
|
||||
|
||||
$config = $this->mapper->load();
|
||||
|
||||
$this->assertNull($config);
|
||||
}
|
||||
|
||||
public function testLoad() {
|
||||
$this->mock->getParameter('config')
|
||||
->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('mail', 'provisioning_settings')
|
||||
->willReturn('[]');
|
||||
|
||||
$config = $this->mapper->load();
|
||||
|
||||
$this->assertInstanceOf(Config::class, $config);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,10 +19,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Service\DefaultAccount;
|
||||
namespace OCA\Mail\Tests\Unit\Service\Provisioning;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Service\DefaultAccount\Config;
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
use OCP\IUser;
|
||||
|
||||
class ConfigTest extends TestCase {
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Service\Provisioning;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\Db\MailAccount;
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
use OCA\Mail\Service\Provisioning\Manager;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\IUser;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ManagerTest extends TestCase {
|
||||
|
||||
/** @var ServiceMockObject */
|
||||
private $mock;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->mock = $this->createServiceMock(Manager::class);
|
||||
$this->manager = $this->mock->getService();
|
||||
}
|
||||
|
||||
public function testProvision() {
|
||||
$config = new TestConfig();
|
||||
$this->mock->getParameter('userManager')
|
||||
->expects($this->once())
|
||||
->method('callForAllUsers');
|
||||
|
||||
$cnt = $this->manager->provision($config);
|
||||
|
||||
$this->assertEquals(0, $cnt);
|
||||
}
|
||||
|
||||
public function testUpdateProvisionSingleUser() {
|
||||
/** @var IUser|MockObject $user */
|
||||
$user = $this->createMock(IUser::class);
|
||||
$config = new TestConfig();
|
||||
$account = $this->createMock(MailAccount::class);
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('findProvisionedAccount')
|
||||
->willReturn($account);
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('update')
|
||||
->with($account);
|
||||
|
||||
$this->manager->provisionSingleUser($config, $user);
|
||||
}
|
||||
|
||||
public function testProvisionSingleUser() {
|
||||
/** @var IUser|MockObject $user */
|
||||
$user = $this->createMock(IUser::class);
|
||||
$config = new TestConfig();
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('findProvisionedAccount')
|
||||
->willThrowException($this->createMock(DoesNotExistException::class));
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('insert');
|
||||
|
||||
$this->manager->provisionSingleUser($config, $user);
|
||||
}
|
||||
|
||||
public function testGetNoConfig() {
|
||||
$config = $this->manager->getConfig();
|
||||
|
||||
$this->assertNull($config);
|
||||
}
|
||||
|
||||
public function testGetConfig() {
|
||||
$config = $this->createMock(Config::class);
|
||||
$this->mock->getParameter('configMapper')
|
||||
->expects($this->once())
|
||||
->method('load')
|
||||
->willReturn($config);
|
||||
|
||||
$cfg = $this->manager->getConfig();
|
||||
|
||||
$this->assertSame($config, $cfg);
|
||||
}
|
||||
|
||||
public function testDeprovision() {
|
||||
$config = new TestConfig();
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('deleteProvisionedAccounts');
|
||||
$this->mock->getParameter('configMapper')
|
||||
->expects($this->once())
|
||||
->method('load')
|
||||
->willReturn($config);
|
||||
$this->mock->getParameter('configMapper')
|
||||
->expects($this->once())
|
||||
->method('save')
|
||||
->willReturn($config);
|
||||
|
||||
$this->manager->deprovision();
|
||||
|
||||
$this->assertEquals(false, $config->jsonSerialize()['active']);
|
||||
}
|
||||
|
||||
public function testImportConfig() {
|
||||
$this->mock->getParameter('configMapper')
|
||||
->expects($this->once())
|
||||
->method('save');
|
||||
|
||||
$this->manager->importConfig([
|
||||
'email' => '%USERID%@domain.com',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testUpdatePasswordNotProvisioned() {
|
||||
/** @var IUser|MockObject $user */
|
||||
$user = $this->createMock(IUser::class);
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('findProvisionedAccount')
|
||||
->with($user)
|
||||
->willThrowException($this->createMock(DoesNotExistException::class));
|
||||
|
||||
$this->manager->updatePassword($user, '123456');
|
||||
}
|
||||
|
||||
public function testUpdatePassword() {
|
||||
/** @var IUser|MockObject $user */
|
||||
$user = $this->createMock(IUser::class);
|
||||
$account = $this->createMock(MailAccount::class);
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('findProvisionedAccount')
|
||||
->willReturn($account);
|
||||
$this->mock->getParameter('mailAccountMapper')
|
||||
->expects($this->once())
|
||||
->method('update')
|
||||
->with($account);
|
||||
|
||||
$this->manager->updatePassword($user, '123456');
|
||||
}
|
||||
|
||||
public function testNewProvisioning() {
|
||||
$this->mock->getParameter('configMapper')
|
||||
->expects($this->once())
|
||||
->method('save');
|
||||
|
||||
$this->manager->newProvisioning(
|
||||
'%USERID%@domain.com',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
993,
|
||||
'ssl',
|
||||
'%USERID%@domain.com',
|
||||
'mx.domain.com',
|
||||
567,
|
||||
'tls'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\mail\tests\Unit\Service\Provisioning;
|
||||
|
||||
use OCA\Mail\Service\Provisioning\Config;
|
||||
|
||||
class TestConfig extends Config {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct([
|
||||
'email' => '%USERID%@domain.com',
|
||||
'imapUser' => '%USERID%@domain.com',
|
||||
'imapHost' => 'mx.domain.com',
|
||||
'imapPort' => 993,
|
||||
'imapSslMode' => 'ssl',
|
||||
'smtpUser' => '%USERID%@domain.com',
|
||||
'smtpHost' => 'mx.domain.com',
|
||||
'smtpPort' => 567,
|
||||
'smtpSslMode' => 'tls',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace OCA\Mail\Tests\Unit\Settings;
|
||||
|
||||
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
|
||||
use ChristophWurst\Nextcloud\Testing\TestCase;
|
||||
use OCA\Mail\AppInfo\Application;
|
||||
use OCA\Mail\Settings\AdminSettings;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
|
||||
class AdminSettingsTest extends TestCase {
|
||||
|
||||
/** @var ServiceMockObject */
|
||||
private $serviceMock;
|
||||
|
||||
/** @var AdminSettings */
|
||||
private $settings;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->serviceMock = $this->createServiceMock(AdminSettings::class);
|
||||
|
||||
$this->settings = $this->serviceMock->getService();
|
||||
}
|
||||
|
||||
public function testGetSection() {
|
||||
$section = $this->settings->getSection();
|
||||
|
||||
$this->assertSame('groupware', $section);
|
||||
}
|
||||
|
||||
public function testGetForm() {
|
||||
$this->serviceMock->getParameter('initialStateService')->expects($this->once())
|
||||
->method('provideInitialState')
|
||||
->with(
|
||||
Application::APP_ID,
|
||||
'provisioning_settings',
|
||||
$this->anything()
|
||||
);
|
||||
$expected = new TemplateResponse(Application::APP_ID, 'settings-admin');
|
||||
|
||||
$form = $this->settings->getForm();
|
||||
|
||||
$this->assertEquals($expected, $form);
|
||||
}
|
||||
|
||||
public function testGetPriority() {
|
||||
$priority = $this->settings->getPriority();
|
||||
|
||||
$this->assertIsInt($priority);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,8 @@ if (process.env.BUNDLE_ANALYZER_TOKEN) {
|
|||
module.exports = {
|
||||
entry: {
|
||||
autoredirect: path.join(__dirname, 'src/autoredirect.js'),
|
||||
mail: path.join(__dirname, 'src/main.js')
|
||||
mail: path.join(__dirname, 'src/main.js'),
|
||||
settings: path.join(__dirname, 'src/main-settings')
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'js'),
|
||||
|
|
Загрузка…
Ссылка в новой задаче