Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appinfo/info.xml4
-rw-r--r--appinfo/routes.php19
-rw-r--r--lib/BackgroundJob/SyncJob.php2
-rw-r--r--lib/BackgroundJob/TrainImportanceClassifierJob.php2
-rw-r--r--lib/Command/DeleteAccount.php2
-rw-r--r--lib/Controller/SettingsController.php70
-rw-r--r--lib/Db/MailAccount.php13
-rw-r--r--lib/Db/MailAccountMapper.php18
-rw-r--r--lib/Db/Provisioning.php169
-rw-r--r--lib/Db/ProvisioningMapper.php145
-rw-r--r--lib/Exception/ValidationException.php (renamed from tests/Unit/Service/Provisioning/TestConfig.php)50
-rw-r--r--lib/Http/Middleware/ProvisioningMiddleware.php8
-rw-r--r--lib/Migration/AddSieveToProvisioningConfig.php85
-rw-r--r--lib/Migration/MigrateProvisioningConfig.php65
-rw-r--r--lib/Migration/ProvisionAccounts.php12
-rw-r--r--lib/Migration/Version1100Date20210419080523.php196
-rw-r--r--lib/Migration/Version1100Date20210419121734.php29
-rw-r--r--lib/Model/IMAPMessage.php2
-rw-r--r--lib/Service/Provisioning/Config.php187
-rw-r--r--lib/Service/Provisioning/ConfigMapper.php62
-rw-r--r--lib/Service/Provisioning/Manager.php167
-rw-r--r--lib/Settings/AdminSettings.php19
-rw-r--r--src/components/settings/AdminSettings.vue194
-rw-r--r--src/components/settings/ProvisionPreview.vue5
-rw-r--r--src/components/settings/ProvisioningSettings.vue274
-rw-r--r--src/main-settings.js3
-rw-r--r--src/service/SettingsService.js31
-rw-r--r--tests/Integration/Db/MailAccountMapperTest.php2
-rw-r--r--tests/Integration/Db/MailAccountTest.php10
-rw-r--r--tests/Integration/Db/ProvisioningMapperTest.php198
-rw-r--r--tests/Unit/Controller/SettingsControllerTest.php48
-rw-r--r--tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php85
-rw-r--r--tests/Unit/Migration/AddSieveToProvisioningConfigTest.php121
-rw-r--r--tests/Unit/Migration/MigrateProvisioningConfigTest.php107
-rw-r--r--tests/Unit/Service/Provisioning/ConfigMapperTest.php86
-rw-r--r--tests/Unit/Service/Provisioning/ConfigTest.php220
-rw-r--r--tests/Unit/Service/Provisioning/ManagerTest.php191
37 files changed, 1500 insertions, 1401 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 7f40a03e4..2e952b004 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -12,7 +12,7 @@
- **🙈 We’re not reinventing the wheel!** Based on the great [Horde](https://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>1.10.0-alpha.3</version>
+ <version>1.10.0-alpha.4</version>
<licence>agpl</licence>
<author>Christoph Wurst</author>
<author>Greta Doçi</author>
@@ -43,8 +43,6 @@
<step>OCA\Mail\Migration\FixCollectedAddresses</step>
<step>OCA\Mail\Migration\FixBackgroundJobs</step>
<step>OCA\Mail\Migration\MakeItineraryExtractorExecutable</step>
- <step>OCA\Mail\Migration\MigrateProvisioningConfig</step>
- <step>OCA\Mail\Migration\AddSieveToProvisioningConfig</step>
<step>OCA\Mail\Migration\ProvisionAccounts</step>
</post-migration>
</repair-steps>
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 4f80ed450..7a1d14649 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -230,13 +230,28 @@ return [
'verb' => 'GET'
],
[
- 'name' => 'settings#provisioning',
+ 'name' => 'settings#index',
+ 'url' => '/api/settings/provisioning',
+ 'verb' => 'GET'
+ ],
+ [
+ 'name' => 'settings#createProvisioning',
'url' => '/api/settings/provisioning',
'verb' => 'POST'
],
[
+ 'name' => 'settings#updateProvisioning',
+ 'url' => '/api/settings/provisioning/{id}',
+ 'verb' => 'POST'
+ ],
+ [
+ 'name' => 'settings#provision',
+ 'url' => '/api/settings/provisioning/all',
+ 'verb' => 'PUT'
+ ],
+ [
'name' => 'settings#deprovision',
- 'url' => '/api/settings/provisioning',
+ 'url' => '/api/settings/provisioning/{id}',
'verb' => 'DELETE'
],
[
diff --git a/lib/BackgroundJob/SyncJob.php b/lib/BackgroundJob/SyncJob.php
index 8d10c549f..b74e47c14 100644
--- a/lib/BackgroundJob/SyncJob.php
+++ b/lib/BackgroundJob/SyncJob.php
@@ -82,7 +82,7 @@ class SyncJob extends TimedJob {
}
$dbAccount = $account->getMailAccount();
- if ($dbAccount->getProvisioned() && $dbAccount->getInboundPassword() === null) {
+ if (!is_null($dbAccount->getProvisioningId()) && $dbAccount->getInboundPassword() === null) {
$this->logger->info("Ignoring cron sync for provisioned account that has no password set yet");
return;
}
diff --git a/lib/BackgroundJob/TrainImportanceClassifierJob.php b/lib/BackgroundJob/TrainImportanceClassifierJob.php
index ca46305d0..abaa11366 100644
--- a/lib/BackgroundJob/TrainImportanceClassifierJob.php
+++ b/lib/BackgroundJob/TrainImportanceClassifierJob.php
@@ -75,7 +75,7 @@ class TrainImportanceClassifierJob extends TimedJob {
}
$dbAccount = $account->getMailAccount();
- if ($dbAccount->getProvisioned() && $dbAccount->getInboundPassword() === null) {
+ if (!is_null($dbAccount->getProvisioningId()) && $dbAccount->getInboundPassword() === null) {
$this->logger->info("Ignoring cron training for provisioned account that has no password set yet");
return;
}
diff --git a/lib/Command/DeleteAccount.php b/lib/Command/DeleteAccount.php
index c32b41fa0..2a7018b3e 100644
--- a/lib/Command/DeleteAccount.php
+++ b/lib/Command/DeleteAccount.php
@@ -70,7 +70,7 @@ class DeleteAccount extends Command {
}
$output->writeLn("<info>Found account with email: " . $account->getEmail() . "</info>");
- if ($account->getMailAccount()->getProvisioned() === true) {
+ if (!is_null($account->getMailAccount()->getProvisioningId())) {
$output->writeLn('<error>This is a provisioned account which can not be deleted from CLI. Use the Provisioning UI instead.</error>');
return 2;
}
diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php
index d65f04f03..2081ea5bb 100644
--- a/lib/Controller/SettingsController.php
+++ b/lib/Controller/SettingsController.php
@@ -26,10 +26,13 @@ declare(strict_types=1);
namespace OCA\Mail\Controller;
use OCA\Mail\AppInfo\Application;
+use OCA\Mail\Exception\ValidationException;
+use OCA\Mail\Http\JsonResponse as HttpJsonResponse;
use OCA\Mail\Service\Provisioning\Manager as ProvisioningManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
+use function array_merge;
class SettingsController extends Controller {
@@ -42,42 +45,45 @@ class SettingsController extends Controller {
$this->provisioningManager = $provisioningManager;
}
- public function provisioning(string $emailTemplate,
- string $imapUser,
- string $imapHost,
- int $imapPort,
- string $imapSslMode,
- string $smtpUser,
- string $smtpHost,
- int $smtpPort,
- string $smtpSslMode,
- bool $sieveEnabled,
- string $sieveUser,
- string $sieveHost,
- int $sievePort,
- string $sieveSslMode): JSONResponse {
- $this->provisioningManager->newProvisioning(
- $emailTemplate,
- $imapUser,
- $imapHost,
- $imapPort,
- $imapSslMode,
- $smtpUser,
- $smtpHost,
- $smtpPort,
- $smtpSslMode,
- $sieveEnabled,
- $sieveUser,
- $sieveHost,
- $sievePort,
- $sieveSslMode
- );
+ public function index(): JSONResponse {
+ $provisionings = $this->provisioningManager->getConfigs();
+ return new JSONResponse($provisionings);
+ }
+
+ public function provision() : JSONResponse {
+ $count = $this->provisioningManager->provision();
+ return new JSONResponse(['count' => $count]);
+ }
+
+ public function createProvisioning(array $data): JSONResponse {
+ try {
+ $this->provisioningManager->newProvisioning($data);
+ } catch (ValidationException $e) {
+ return HttpJsonResponse::fail([$e->getFields()]);
+ }
return new JSONResponse([]);
}
- public function deprovision(): JSONResponse {
- $this->provisioningManager->deprovision();
+ public function updateProvisioning(int $id, array $data): JSONResponse {
+ try {
+ $this->provisioningManager->updateProvisioning(array_merge(
+ $data,
+ ['id' => $id]
+ ));
+ } catch (ValidationException $e) {
+ return HttpJsonResponse::fail([$e->getFields()]);
+ }
+
+ return new JSONResponse([]);
+ }
+
+ public function deprovision(int $id): JSONResponse {
+ $provisioning = $this->provisioningManager->getConfigById($id);
+
+ if ($provisioning !== null) {
+ $this->provisioningManager->deprovision($provisioning);
+ }
return new JSONResponse([]);
}
diff --git a/lib/Db/MailAccount.php b/lib/Db/MailAccount.php
index a41b0528c..933eb5001 100644
--- a/lib/Db/MailAccount.php
+++ b/lib/Db/MailAccount.php
@@ -63,8 +63,8 @@ use OCP\AppFramework\Db\Entity;
* @method void setLastMailboxSync(int $time)
* @method string getEditorMode()
* @method void setEditorMode(string $editorMode)
- * @method bool|null getProvisioned()
- * @method void setProvisioned(bool $provisioned)
+ * @method int|null getProvisioningId()
+ * @method void setProvisioningId(int $provisioningId)
* @method int getOrder()
* @method void setOrder(int $order)
* @method bool|null getShowSubscribedOnly()
@@ -109,7 +109,6 @@ class MailAccount extends Entity {
protected $signature;
protected $lastMailboxSync;
protected $editorMode;
- protected $provisioned;
protected $order;
protected $showSubscribedOnly;
protected $personalNamespace;
@@ -138,6 +137,10 @@ class MailAccount extends Entity {
/** @var bool */
protected $signatureAboveQuote = false;
+ /** @var int|null */
+ protected $provisioningId;
+
+
/**
* @param array $params
*/
@@ -193,7 +196,7 @@ class MailAccount extends Entity {
$this->addType('inboundPort', 'integer');
$this->addType('outboundPort', 'integer');
$this->addType('lastMailboxSync', 'integer');
- $this->addType('provisioned', 'boolean');
+ $this->addType('provisioning_id', 'integer');
$this->addType('order', 'integer');
$this->addType('showSubscribedOnly', 'boolean');
$this->addType('personalNamespace', 'string');
@@ -221,7 +224,7 @@ class MailAccount extends Entity {
'imapSslMode' => $this->getInboundSslMode(),
'signature' => $this->getSignature(),
'editorMode' => $this->getEditorMode(),
- 'provisioned' => ($this->getProvisioned() === true),
+ 'provisioningId' => $this->getProvisioningId(),
'showSubscribedOnly' => ($this->getShowSubscribedOnly() === true),
'personalNamespace' => $this->getPersonalNamespace(),
'draftsMailboxId' => $this->getDraftsMailboxId(),
diff --git a/lib/Db/MailAccountMapper.php b/lib/Db/MailAccountMapper.php
index 1dccbb674..8d6586fcd 100644
--- a/lib/Db/MailAccountMapper.php
+++ b/lib/Db/MailAccountMapper.php
@@ -110,7 +110,7 @@ class MailAccountMapper extends QBMapper {
->from($this->getTableName())
->where(
$qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID())),
- $qb->expr()->eq('provisioned', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
+ $qb->expr()->isNotNull('provisioning_id')
);
return $this->findEntity($query);
@@ -131,11 +131,23 @@ class MailAccountMapper extends QBMapper {
return $this->update($account);
}
- public function deleteProvisionedAccounts(): void {
+ public function deleteProvisionedAccounts(int $provisioningId): void {
$qb = $this->db->getQueryBuilder();
$delete = $qb->delete($this->getTableName())
- ->where($qb->expr()->eq('provisioned', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)));
+ ->where($qb->expr()->eq('provisioning_id', $qb->createNamedParameter($provisioningId, IQueryBuilder::PARAM_BOOL)));
+
+ $delete->execute();
+ }
+
+ public function deleteProvisionedAccountsByUid(string $uid): void {
+ $qb = $this->db->getQueryBuilder();
+
+ $delete = $qb->delete($this->getTableName())
+ ->where(
+ $qb->expr()->eq('user_id', $qb->createNamedParameter($uid)),
+ $qb->expr()->isNotNull('provisioning_id')
+ );
$delete->execute();
}
diff --git a/lib/Db/Provisioning.php b/lib/Db/Provisioning.php
new file mode 100644
index 000000000..97d3c7a81
--- /dev/null
+++ b/lib/Db/Provisioning.php
@@ -0,0 +1,169 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @author 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @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\Db;
+
+use JsonSerializable;
+use OCP\AppFramework\Db\Entity;
+use OCP\IUser;
+
+/**
+ * @method string getProvisioningDomain()
+ * @method void setProvisioningDomain(string $provisioningDomain)
+ * @method string getEmailTemplate()
+ * @method void setEmailTemplate(string $emailTemplate)
+ * @method string getImapUser()
+ * @method void setImapUser(string $imapUser)
+ * @method string getImapHost()
+ * @method void setImapHost(string $imapHost)
+ * @method int getImapPort()
+ * @method void setImapPort(int $imapPort)
+ * @method string getImapSslMode()
+ * @method void setImapSslMode(string $imapSslMode)
+ * @method string getSmtpUser()
+ * @method void setSmtpUser(string $smtpUser)
+ * @method string getSmtpHost()
+ * @method void setSmtpHost(string $smtpHost)
+ * @method int getSmtpPort()
+ * @method void setSmtpPort(int $smtpPort)
+ * @method string getSmtpSslMode()
+ * @method void setSmtpSslMode(string $smtpSslMode)
+ * @method bool|null getSieveEnabled()
+ * @method void setSieveEnabled(bool $sieveEnabled)
+ * @method string|null getSieveHost()
+ * @method void setSieveHost(?string $sieveHost)
+ * @method int|null getSievePort()
+ * @method void setSievePort(?int $sievePort)
+ * @method string|null getSieveSslMode()
+ * @method void setSieveSslMode(?string $sieveSslMode)
+ * @method string|null getSieveUser()
+ * @method void setSieveUser(?string $sieveUser)
+ */
+class Provisioning extends Entity implements JsonSerializable {
+ public const WILDCARD = '*';
+
+ protected $provisioningDomain;
+ protected $emailTemplate;
+ protected $imapUser;
+ protected $imapHost;
+ protected $imapPort;
+ protected $imapSslMode;
+ protected $smtpUser;
+ protected $smtpHost;
+ protected $smtpPort;
+ protected $smtpSslMode;
+ protected $sieveEnabled;
+ protected $sieveUser;
+ protected $sieveHost;
+ protected $sievePort;
+ protected $sieveSslMode;
+
+ public function __construct() {
+ $this->addType('imapPort', 'integer');
+ $this->addType('smtpPort', 'integer');
+ $this->addType('sieveEnabled', 'boolean');
+ $this->addType('sievePort', 'integer');
+ }
+ /**
+ * @return array
+ */
+ public function jsonSerialize() {
+ return [
+ 'id' => $this->getId(),
+ 'provisioningDomain' => $this->getProvisioningDomain(),
+ 'emailTemplate' => $this->getEmailTemplate(),
+ 'imapUser' => $this->getImapUser(),
+ 'imapHost' => $this->getImapHost(),
+ 'imapPort' => $this->getImapPort(),
+ 'imapSslMode' => $this->getImapSslMode(),
+ 'smtpUser' => $this->getSmtpUser(),
+ 'smtpHost' => $this->getSmtpHost(),
+ 'smtpPort' => $this->getSmtpPort(),
+ 'smtpSslMode' => $this->getSmtpSslMode(),
+ 'sieveEnabled' => $this->getSieveEnabled(),
+ 'sieveUser' => $this->getSieveUser(),
+ 'sieveHost' => $this->getSieveHost(),
+ 'sievePort' => $this->getSievePort(),
+ 'sieveSslMode' => $this->getSieveSslMode(),
+ ];
+ }
+
+ /**
+ * @return string
+ */
+ public function buildImapUser(IUser $user) {
+ if (!is_null($this->getImapUser())) {
+ return $this->buildUserEmail($this->getImapUser(), $user);
+ }
+ return $this->buildEmail($user);
+ }
+
+ /**
+ * @param IUser $user
+ * @return string
+ */
+ public function buildEmail(IUser $user) {
+ return $this->buildUserEmail($this->getEmailTemplate(), $user);
+ }
+
+ /**
+ * Replace %USERID% and %EMAIL% to allow special configurations
+ *
+ * @param string $original
+ * @param IUser $user
+ * @return string
+ */
+ private function buildUserEmail(string $original, IUser $user) {
+ if ($user->getUID() !== null) {
+ $original = str_replace('%USERID%', $user->getUID(), $original);
+ }
+ if ($user->getEMailAddress() !== null) {
+ $original = str_replace('%EMAIL%', $user->getEMailAddress(), $original);
+ }
+ return $original;
+ }
+
+ /**
+ * @param IUser $user
+ * @return string
+ */
+ public function buildSmtpUser(IUser $user) {
+ if (!is_null($this->getSmtpUser())) {
+ return $this->buildUserEmail($this->getSmtpUser(), $user);
+ }
+ return $this->buildEmail($user);
+ }
+
+ /**
+ * @param IUser $user
+ * @return string
+ */
+ public function buildSieveUser(IUser $user) {
+ if (!is_null($this->getSieveUser())) {
+ return $this->buildUserEmail($this->getSieveUser(), $user);
+ }
+ return $this->buildEmail($user);
+ }
+}
diff --git a/lib/Db/ProvisioningMapper.php b/lib/Db/ProvisioningMapper.php
new file mode 100644
index 000000000..09eec6281
--- /dev/null
+++ b/lib/Db/ProvisioningMapper.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @author 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @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\Db;
+
+use OCA\Mail\Exception\ValidationException;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @template-extends QBMapper<Provisioning>
+ */
+class ProvisioningMapper extends QBMapper {
+
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(IDBConnection $db, LoggerInterface $logger) {
+ parent::__construct($db, 'mail_provisionings');
+ $this->logger = $logger;
+ }
+
+ /**
+ * Should return the wildcard domain last!
+ *
+ * @return Provisioning[]
+ */
+ public function getAll() : array {
+ $qb = $this->db->getQueryBuilder();
+ $qb = $qb->select('*')
+ ->from($this->getTableName())
+ ->orderBy('provisioning_domain', 'desc');
+ try {
+ return $this->findEntities($qb);
+ } catch (DoesNotExistException $e) {
+ $this->logger->error('No provisioning configs available');
+ return [];
+ }
+ }
+
+ /**
+ * @param array $data
+ * @return Provisioning
+ * @throws ValidationException
+ */
+ public function validate(array $data) : Provisioning {
+ $exception = new ValidationException();
+
+ if (!isset($data['provisioningDomain']) || $data['provisioningDomain'] === '') {
+ $exception->setField('provisioningDomain', false);
+ }
+ if (!isset($data['emailTemplate']) || $data['emailTemplate'] === '') {
+ $exception->setField('emailTemplate', false);
+ }
+ if (!isset($data['imapUser']) || $data['imapUser'] === '') {
+ $exception->setField('imapUser', false);
+ }
+ if (!isset($data['imapHost']) || $data['imapHost'] === '') {
+ $exception->setField('imapHost', false);
+ }
+ if (!isset($data['imapPort']) || (int)$data['imapPort'] === 0) {
+ $exception->setField('imapHost', false);
+ }
+ if (!isset($data['imapSslMode']) || $data['imapSslMode'] === '') {
+ $exception->setField('imapSslMode', false);
+ }
+ if (!isset($data['smtpUser']) || $data['smtpUser'] === '') {
+ $exception->setField('smtpUser', false);
+ }
+ if (!isset($data['smtpHost']) || $data['smtpHost'] === '') {
+ $exception->setField('smtpHost', false);
+ }
+ if (!isset($data['smtpPort']) || (int)$data['smtpPort'] === 0) {
+ $exception->setField('smtpPort', false);
+ }
+ if (!isset($data['smtpSslMode']) || $data['smtpSslMode'] === '') {
+ $exception->setField('smtpSslMode', false);
+ }
+
+ if (!empty($exception->getFields())) {
+ throw $exception;
+ }
+
+
+ $provisioning = new Provisioning();
+ $provisioning->setId($data['id'] ?? null);
+ $provisioning->setProvisioningDomain($data['provisioningDomain']);
+ $provisioning->setEmailTemplate($data['emailTemplate']);
+ $provisioning->setImapUser($data['imapUser']);
+ $provisioning->setImapHost($data['imapHost']);
+ $provisioning->setImapPort((int)$data['imapPort']);
+ $provisioning->setImapSslMode($data['imapSslMode']);
+ $provisioning->setSmtpUser($data['smtpUser']);
+ $provisioning->setSmtpHost($data['smtpHost']);
+ $provisioning->setSmtpPort((int)$data['smtpPort']);
+ $provisioning->setSmtpSslMode($data['smtpSslMode']);
+
+ $provisioning->setSieveEnabled((bool)$data['sieveEnabled']);
+ $provisioning->setSieveHost($data['sieveHost'] ?? '');
+ $provisioning->setSieveUser($data['sieveUser'] ?? '');
+ $provisioning->setSievePort($data['sievePort'] ?? null);
+ $provisioning->setSieveSslMode($data['sieveSslMode'] ?? '');
+
+ return $provisioning;
+ }
+
+ public function get(int $id): ?Provisioning {
+ $qb = $this->db->getQueryBuilder();
+ $qb = $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id), IQueryBuilder::PARAM_INT));
+ try {
+ return $this->findEntity($qb);
+ } catch (DoesNotExistException $e) {
+ $this->logger->error('Could not find entry with ID #' . $id);
+ return null;
+ }
+ }
+}
diff --git a/tests/Unit/Service/Provisioning/TestConfig.php b/lib/Exception/ValidationException.php
index 9ebf3157a..217ca635a 100644
--- a/tests/Unit/Service/Provisioning/TestConfig.php
+++ b/lib/Exception/ValidationException.php
@@ -3,9 +3,9 @@
declare(strict_types=1);
/**
- * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @copyright 2021 Anna Larch <anna@nextcloud.com>
*
- * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author 2021 Anna Larch <anna@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -21,29 +21,37 @@ declare(strict_types=1);
*
* 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;
+namespace OCA\Mail\Exception;
+
+use Exception;
+use OCP\AppFramework\Http;
-use OCA\Mail\Service\Provisioning\Config;
+class ValidationException extends Exception {
+ /** @var bool[] */
+ private $fields;
-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',
- 'sieveEnabled' => false,
- 'sieveHost' => '',
- 'sievePort' => 4190,
- 'sieveUser' => '',
- 'sieveSslMode' => 'tls',
- ]);
+ $this->fields = [];
+ }
+
+ public function getHttpCode(): int {
+ return Http::STATUS_BAD_REQUEST;
+ }
+
+ public function getFields(): array {
+ return $this->fields;
+ }
+
+ public function setField(string $key, bool $validates): void {
+ $this->fields[$key] = $validates;
+ }
+
+ public function setFields(array $fields): void {
+ foreach ($fields as $key => $validates) {
+ $this->setField($key, $validates);
+ }
}
}
diff --git a/lib/Http/Middleware/ProvisioningMiddleware.php b/lib/Http/Middleware/ProvisioningMiddleware.php
index 47ff642fe..3acc1c8d9 100644
--- a/lib/Http/Middleware/ProvisioningMiddleware.php
+++ b/lib/Http/Middleware/ProvisioningMiddleware.php
@@ -64,12 +64,12 @@ class ProvisioningMiddleware extends Middleware {
// Nothing to update
return;
}
- $config = $this->provisioningManager->getConfig();
- if ($config === null || !$config->isActive()) {
- return;
+ $configs = $this->provisioningManager->getConfigs();
+ if (empty($configs)) {
+ return null;
}
try {
- $this->provisioningManager->provisionSingleUser($config, $user);
+ $this->provisioningManager->provisionSingleUser($configs, $user);
$this->provisioningManager->updatePassword(
$user,
$this->credentialStore->getLoginCredentials()->getPassword()
diff --git a/lib/Migration/AddSieveToProvisioningConfig.php b/lib/Migration/AddSieveToProvisioningConfig.php
deleted file mode 100644
index e871ff1cc..000000000
--- a/lib/Migration/AddSieveToProvisioningConfig.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- *
- * 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\Config as ProvisioningConfig;
-use OCA\Mail\Service\Provisioning\ConfigMapper as ProvisioningConfigMapper;
-use OCP\IConfig;
-use OCP\Migration\IOutput;
-use OCP\Migration\IRepairStep;
-
-class AddSieveToProvisioningConfig implements IRepairStep {
-
- /** @var IConfig */
- private $config;
-
- /** @var ProvisioningConfigMapper */
- private $configMapper;
-
- public function __construct(IConfig $config, ProvisioningConfigMapper $configMapper) {
- $this->config = $config;
- $this->configMapper = $configMapper;
- }
-
- public function getName(): string {
- return 'Add sieve defaults to provisioning config';
- }
-
- public function run(IOutput $output) {
- if (!$this->shouldRun()) {
- return;
- }
-
- $config = $this->configMapper->load();
- if ($config === null) {
- return;
- }
-
- $reflectionClass = new \ReflectionClass(ProvisioningConfig::class);
- $reflectionProperty = $reflectionClass->getProperty('data');
-
- $reflectionProperty->setAccessible(true);
- $data = $reflectionProperty->getValue($config);
-
- if (!isset($data['sieveEnabled'])) {
- $data = array_merge($data, [
- 'sieveEnabled' => false,
- 'sieveHost' => '',
- 'sievePort' => 4190,
- 'sieveUser' => '',
- 'sieveSslMode' => 'tls',
- ]);
- }
-
- $reflectionProperty->setValue($config, $data);
- $this->configMapper->save($config);
-
- $output->info('added sieve defaults to provisioning config');
- }
-
- protected function shouldRun(): bool {
- $appVersion = $this->config->getAppValue('mail', 'installed_version', '0.0.0');
- return version_compare($appVersion, '1.9.0', '<');
- }
-}
diff --git a/lib/Migration/MigrateProvisioningConfig.php b/lib/Migration/MigrateProvisioningConfig.php
deleted file mode 100644
index 12b90c8f8..000000000
--- a/lib/Migration/MigrateProvisioningConfig.php
+++ /dev/null
@@ -1,65 +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\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");
- }
-}
diff --git a/lib/Migration/ProvisionAccounts.php b/lib/Migration/ProvisionAccounts.php
index 8487492ca..268e1a99d 100644
--- a/lib/Migration/ProvisionAccounts.php
+++ b/lib/Migration/ProvisionAccounts.php
@@ -43,17 +43,7 @@ class ProvisionAccounts implements IRepairStep {
}
public function run(IOutput $output) {
- $config = $this->provisioningManager->getConfig();
- if ($config === null) {
- $output->info("No Mail provisioning config set");
- return;
- }
- if (!$config->isActive()) {
- $output->info("Mail provisioning is disabled");
- return;
- }
-
- $cnt = $this->provisioningManager->provision($config);
+ $cnt = $this->provisioningManager->provision();
$output->info("$cnt accounts provisioned");
}
}
diff --git a/lib/Migration/Version1100Date20210419080523.php b/lib/Migration/Version1100Date20210419080523.php
new file mode 100644
index 000000000..5c84fee7b
--- /dev/null
+++ b/lib/Migration/Version1100Date20210419080523.php
@@ -0,0 +1,196 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\Mail\Migration;
+
+use Closure;
+use JsonException;
+use OCA\Mail\AppInfo\Application;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+use Psr\Log\LoggerInterface;
+
+class Version1100Date20210419080523 extends SimpleMigrationStep {
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /** @var LoggerInterface */
+ protected $logger;
+
+ public function __construct(IConfig $config, IDBConnection $connection, LoggerInterface $logger) {
+ $this->config = $config;
+ $this->connection = $connection;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ $schema = $schemaClosure();
+
+ if (!$schema->hasTable('mail_provisionings')) {
+ $provisioningTable = $schema->createTable('mail_provisionings');
+ $provisioningTable->addColumn('id', 'integer', [
+ 'autoincrement' => true,
+ 'notnull' => true,
+ 'length' => 4,
+ ]);
+ $provisioningTable->addColumn('provisioning_domain', 'string', [
+ 'notnull' => true,
+ 'length' => 63,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('email_template', 'string', [
+ 'notnull' => true,
+ 'length' => 255,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('imap_user', 'string', [
+ 'notnull' => true,
+ 'length' => 128,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('imap_host', 'string', [
+ 'notnull' => true,
+ 'length' => 255,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('imap_port', 'smallint', [
+ 'notnull' => true,
+ 'unsigned' => true,
+ ]);
+ $provisioningTable->addColumn('imap_ssl_mode', 'string', [
+ 'notnull' => true,
+ 'length' => 64,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('smtp_user', 'string', [
+ 'notnull' => true,
+ 'length' => 128,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('smtp_host', 'string', [
+ 'notnull' => true,
+ 'length' => 255,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('smtp_port', 'smallint', [
+ 'notnull' => true,
+ 'unsigned' => true,
+ ]);
+ $provisioningTable->addColumn('smtp_ssl_mode', 'string', [
+ 'notnull' => true,
+ 'length' => 64,
+ 'default' => '',
+ ]);
+ $provisioningTable->addColumn('sieve_enabled', 'boolean', [
+ 'notnull' => false,
+ 'default' => false,
+ ]);
+ $provisioningTable->addColumn('sieve_user', 'string', [
+ 'notnull' => false,
+ 'length' => 128,
+ ]);
+ $provisioningTable->addColumn('sieve_host', 'string', [
+ 'notnull' => false,
+ 'length' => 128,
+ ]);
+ $provisioningTable->addColumn('sieve_port', 'smallint', [
+ 'notnull' => false,
+ 'unsigned' => true,
+ ]);
+ $provisioningTable->addColumn('sieve_ssl_mode', 'string', [
+ 'notnull' => false,
+ 'length' => 64,
+ ]);
+ $provisioningTable->setPrimaryKey(['id']);
+ $provisioningTable->addUniqueIndex(
+ [
+ 'provisioning_domain',
+ ],
+ 'mail_provsng_dm_idx'
+ );
+ }
+
+ $accountsTable = $schema->getTable('mail_accounts');
+ $accountsTable->addColumn('provisioning_id', 'integer', [
+ 'length' => 4,
+ 'notnull' => false,
+ ]);
+
+ return $schema;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+ // Fetch old config
+ $raw = $this->config->getAppValue(
+ Application::APP_ID,
+ 'provisioning_settings'
+ );
+ if ($raw === '') {
+ // Not config set yet
+ return;
+ }
+
+ try {
+ $conf = json_decode($raw, true, 10, JSON_THROW_ON_ERROR);
+ } catch (JsonException $e) {
+ $this->logger->error('Json decode for old provisioning config failed: ' . $e->getMessage() . ' - building manual config', [
+ 'exception' => $e,
+ ]);
+ // build config manually
+ $conf = [];
+ }
+
+ // create first entry
+ $insertQb = $this->connection->getQueryBuilder();
+ $insertQb->insert('mail_provisionings');
+ $insertQb->setValue('provisioning_domain', $insertQb->createNamedParameter('*')); // wildcard domain for this provisioning
+ $insertQb->setValue('email_template', $insertQb->createNamedParameter($conf['email'] ?? '%USERID%@domain.com'));
+ $insertQb->setValue('imap_user', $insertQb->createNamedParameter($conf['imapUser'] ?? '%USERID%@domain.com'));
+ $insertQb->setValue('imap_host', $insertQb->createNamedParameter($conf['imapHost'] ?? 'imap.domain.com'));
+ $insertQb->setValue('imap_port', $insertQb->createNamedParameter($conf['imapPort'] ?? 993, IQueryBuilder::PARAM_INT));
+ $insertQb->setValue('imap_ssl_mode', $insertQb->createNamedParameter($conf['imapSslMode'] ?? 'ssl'));
+ $insertQb->setValue('smtp_user', $insertQb->createNamedParameter($conf['smtpUser'] ?? '%USERID%@domain.com'));
+ $insertQb->setValue('smtp_host', $insertQb->createNamedParameter($conf['smtpHost'] ?? 'smtp.domain.com'));
+ $insertQb->setValue('smtp_port', $insertQb->createNamedParameter($conf['smtpPort'] ?? 587, IQueryBuilder::PARAM_INT));
+ $insertQb->setValue('smtp_ssl_mode', $insertQb->createNamedParameter($conf['smtpSslMode'] ?? 'tls'));
+ $insertQb->setValue('sieve_enabled', $insertQb->createNamedParameter((bool)($conf['sieveEnabled'] ?? false),IQueryBuilder::PARAM_BOOL));
+ $insertQb->setValue('sieve_user', $insertQb->createNamedParameter($conf['sieveUser'] ?? ''));
+ $insertQb->setValue('sieve_host', $insertQb->createNamedParameter($conf['sieveHost'] ?? ''));
+ $insertQb->setValue('sieve_port', $insertQb->createNamedParameter($conf['sievePort'] ?? 4190, IQueryBuilder::PARAM_INT));
+ $insertQb->setValue('sieve_ssl_mode', $insertQb->createNamedParameter($conf['sieveSslMode'] ?? ''));
+ $insertQb->execute();
+ $id = $insertQb->getLastInsertId();
+
+ // set wildcard provisioning config for all provisioned accounts so we don't use state
+ $updateQb = $this->connection->getQueryBuilder();
+ $updateQb = $updateQb->update('mail_accounts')
+ ->set('provisioning_id', $updateQb->createNamedParameter($id, IQueryBuilder::PARAM_INT))
+ ->where($updateQb->expr()->eq('provisioned', $updateQb->createNamedParameter('true', IQueryBuilder::PARAM_BOOL)));
+ $updateQb->execute();
+
+ $this->config->deleteAppValue(
+ Application::APP_ID,
+ 'provisioning_settings'
+ );
+ }
+}
diff --git a/lib/Migration/Version1100Date20210419121734.php b/lib/Migration/Version1100Date20210419121734.php
new file mode 100644
index 000000000..80bf9509d
--- /dev/null
+++ b/lib/Migration/Version1100Date20210419121734.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\Mail\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version1100Date20210419121734 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $accounts = $schema->getTable('mail_accounts');
+ $accounts->dropColumn('provisioned');
+
+ return $schema;
+ }
+}
diff --git a/lib/Model/IMAPMessage.php b/lib/Model/IMAPMessage.php
index 42d82834c..e1393d8ac 100644
--- a/lib/Model/IMAPMessage.php
+++ b/lib/Model/IMAPMessage.php
@@ -766,7 +766,7 @@ class IMAPMessage implements IMessage, JsonSerializable {
$t = [];
foreach ($tags as $keyword) {
// Map the old $important to $label1 until we have caught them all
- if ($keyword === '$important' || $keyword === 'important') {
+ if ($keyword === '$important') {
$keyword = Tag::LABEL_IMPORTANT;
}
$tag = new Tag();
diff --git a/lib/Service/Provisioning/Config.php b/lib/Service/Provisioning/Config.php
deleted file mode 100644
index 74b8cda8d..000000000
--- a/lib/Service/Provisioning/Config.php
+++ /dev/null
@@ -1,187 +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\Provisioning;
-
-use JsonSerializable;
-use OCP\IUser;
-
-class Config implements JsonSerializable {
- private const VERSION = 1;
-
- /** @var mixed[] */
- private $data;
-
- /**
- * @param array $data
- */
- public function __construct(array $data) {
- $this->data = $data;
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildEmail(IUser $user) {
- return $this->buildUserEmail($this->data['email'], $user);
- }
-
- /**
- * @return string
- */
- public function getImapHost() {
- return $this->data['imapHost'];
- }
-
- /**
- * @return int
- */
- public function getImapPort(): int {
- return (int) $this->data['imapPort'];
- }
-
- /**
- * @return string
- */
- public function buildImapUser(IUser $user) {
- if (isset($this->data['imapUser'])) {
- return $this->buildUserEmail($this->data['imapUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getImapSslMode() {
- return $this->data['imapSslMode'];
- }
-
- /**
- * @return string
- */
- public function getSmtpHost() {
- return $this->data['smtpHost'];
- }
-
- /**
- * @return int
- */
- public function getSmtpPort(): int {
- return (int) $this->data['smtpPort'];
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildSmtpUser(IUser $user) {
- if (isset($this->data['smtpUser'])) {
- return $this->buildUserEmail($this->data['smtpUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getSmtpSslMode() {
- return $this->data['smtpSslMode'];
- }
-
- /**
- * @return boolean
- */
- public function getSieveEnabled(): bool {
- return (bool)$this->data['sieveEnabled'];
- }
-
- /**
- * @return string
- */
- public function getSieveHost() {
- return $this->data['sieveHost'];
- }
-
- /**
- * @return int
- */
- public function getSievePort(): int {
- return (int)$this->data['sievePort'];
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildSieveUser(IUser $user) {
- if (isset($this->data['sieveUser'])) {
- return $this->buildUserEmail($this->data['sieveUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getSieveSslMode() {
- return $this->data['sieveSslMode'];
- }
-
- /**
- * Replace %USERID% and %EMAIL% to allow special configurations
- *
- * @param string $original
- * @param IUser $user
- * @return string
- */
- private function buildUserEmail(string $original, IUser $user) {
- if ($user->getUID() !== null) {
- $original = str_replace('%USERID%', $user->getUID(), $original);
- }
- 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 isActive(): bool {
- return (bool) ($this->data['active'] ?? true);
- }
-
- public function jsonSerialize() {
- return array_merge(
- [
- 'active' => false,
- 'version' => self::VERSION,
- ],
- $this->data
- );
- }
-}
diff --git a/lib/Service/Provisioning/ConfigMapper.php b/lib/Service/Provisioning/ConfigMapper.php
deleted file mode 100644
index 2f9b2de31..000000000
--- a/lib/Service/Provisioning/ConfigMapper.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?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;
- }
-}
diff --git a/lib/Service/Provisioning/Manager.php b/lib/Service/Provisioning/Manager.php
index 742c87f13..8cc9c2e06 100644
--- a/lib/Service/Provisioning/Manager.php
+++ b/lib/Service/Provisioning/Manager.php
@@ -23,9 +23,14 @@ declare(strict_types=1);
namespace OCA\Mail\Service\Provisioning;
+use Horde_Mail_Rfc822_Address;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Db\MailAccountMapper;
+use OCA\Mail\Db\Provisioning;
+use OCA\Mail\Db\ProvisioningMapper;
+use OCA\Mail\Exception\ValidationException;
use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\ICrypto;
@@ -36,8 +41,8 @@ class Manager {
/** @var IUserManager */
private $userManager;
- /** @var ConfigMapper */
- private $configMapper;
+ /** @var ProvisioningMapper */
+ private $provisioningMapper;
/** @var MailAccountMapper */
private $mailAccountMapper;
@@ -49,85 +54,106 @@ class Manager {
private $logger;
public function __construct(IUserManager $userManager,
- ConfigMapper $configMapper,
+ ProvisioningMapper $provisioningMapper,
MailAccountMapper $mailAccountMapper,
ICrypto $crypto,
LoggerInterface $logger) {
$this->userManager = $userManager;
- $this->configMapper = $configMapper;
+ $this->provisioningMapper = $provisioningMapper;
$this->mailAccountMapper = $mailAccountMapper;
$this->crypto = $crypto;
$this->logger = $logger;
}
- public function getConfig(): ?Config {
- return $this->configMapper->load();
+ public function getConfigById(int $provisioningId): ?Provisioning {
+ return $this->provisioningMapper->get($provisioningId);
}
- public function provision(Config $config): int {
+ public function getConfigs(): array {
+ return $this->provisioningMapper->getAll();
+ }
+
+ public function provision(): int {
$cnt = 0;
- $this->userManager->callForAllUsers(function (IUser $user) use ($config, &$cnt) {
- $this->provisionSingleUser($config, $user);
- $cnt++;
+ $configs = $this->getConfigs();
+ $this->userManager->callForAllUsers(function (IUser $user) use ($configs, &$cnt) {
+ if ($this->provisionSingleUser($configs, $user) === true) {
+ $cnt++;
+ }
});
return $cnt;
}
- public function provisionSingleUser(Config $config, IUser $user): void {
+ /**
+ * @param Provisioning[] $provisionings
+ */
+ public function provisionSingleUser(array $provisionings, IUser $user): bool {
+ $provisioning = $this->findMatchingConfig($provisionings, $user);
+
+ if ($provisioning === null) {
+ return false;
+ }
+
try {
+ // TODO: match by UID only, catch multiple objects returned below and delete all those accounts
$existing = $this->mailAccountMapper->findProvisionedAccount($user);
$this->mailAccountMapper->update(
- $this->updateAccount($user, $existing, $config)
+ $this->updateAccount($user, $existing, $provisioning)
);
+ return true;
} catch (DoesNotExistException $e) {
// Fine, then we create a new one
$new = new MailAccount();
$new->setUserId($user->getUID());
- $new->setProvisioned(true);
$this->mailAccountMapper->insert(
- $this->updateAccount($user, $new, $config)
+ $this->updateAccount($user, $new, $provisioning)
);
+ return true;
+ } catch (MultipleObjectsReturnedException $e) {
+ // This is unlikely to happen but not impossible.
+ // Let's wipe any existing accounts and start fresh
+ $this->mailAccountMapper->deleteProvisionedAccountsByUid($user->getUID());
+
+ $new = new MailAccount();
+ $new->setUserId($user->getUID());
+
+ $this->mailAccountMapper->insert(
+ $this->updateAccount($user, $new, $provisioning)
+ );
+ return true;
}
+ return false;
}
- public function newProvisioning(string $email,
- string $imapUser,
- string $imapHost,
- int $imapPort,
- string $imapSslMode,
- string $smtpUser,
- string $smtpHost,
- int $smtpPort,
- string $smtpSslMode,
- bool $sieveEnabled,
- string $sieveUser,
- string $sieveHost,
- int $sievePort,
- string $sieveSslMode): 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,
- 'sieveEnabled' => $sieveEnabled,
- 'sieveUser' => $sieveUser,
- 'sieveHost' => $sieveHost,
- 'sievePort' => $sievePort,
- 'sieveSslMode' => $sieveSslMode,
- ]));
-
- $this->provision($config);
+ public function newProvisioning(array $data): void {
+ try {
+ $provisioning = $this->provisioningMapper->validate(
+ $data
+ );
+ } catch (ValidationException $e) {
+ throw $e;
+ }
+ $this->provisioningMapper->insert($provisioning);
}
- private function updateAccount(IUser $user, MailAccount $account, Config $config): MailAccount {
+ public function updateProvisioning(array $data): void {
+ try {
+ $provisioning = $this->provisioningMapper->validate(
+ $data
+ );
+ } catch (ValidationException $e) {
+ throw $e;
+ }
+
+ $this->provisioningMapper->update($provisioning);
+ }
+
+ private function updateAccount(IUser $user, MailAccount $account, Provisioning $config): MailAccount {
+ // Set the ID to make sure it reflects when the account switches from one config to another
+ $account->setProvisioningId($config->getId());
+
$account->setEmail($config->buildEmail($user));
$account->setName($user->getDisplayName());
$account->setInboundUser($config->buildImapUser($user));
@@ -155,26 +181,9 @@ class Manager {
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'];
- }
- $data['active'] = true;
-
- return $this->configMapper->save(new Config($data));
+ public function deprovision(Provisioning $provisioning): void {
+ $this->mailAccountMapper->deleteProvisionedAccounts($provisioning->getId());
+ $this->provisioningMapper->delete($provisioning);
}
public function updatePassword(IUser $user, string $password): void {
@@ -198,4 +207,26 @@ class Manager {
// Nothing to update
}
}
+
+ /**
+ * @param Provisioning[] $provisionings
+ */
+ private function findMatchingConfig(array $provisionings, IUser $user): ?Provisioning {
+ foreach ($provisionings as $provisioning) {
+ if ($provisioning->getProvisioningDomain() === Provisioning::WILDCARD) {
+ return $provisioning;
+ }
+
+ $email = $user->getEMailAddress();
+ if ($email === null) {
+ continue;
+ }
+ $rfc822Address = new Horde_Mail_Rfc822_Address($email);
+ if ($rfc822Address->matchDomain($provisioning->getProvisioningDomain())) {
+ return $provisioning;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php
index 7e4c47c98..2a8d0fd4e 100644
--- a/lib/Settings/AdminSettings.php
+++ b/lib/Settings/AdminSettings.php
@@ -26,7 +26,6 @@ declare(strict_types=1);
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;
@@ -50,23 +49,7 @@ class AdminSettings implements ISettings {
$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',
- 'sieveEnabled' => false,
- 'sieveUser' => '%USERID%@domain.com',
- 'sieveHost' => 'imap.domain.com',
- 'sievePort' => 4190,
- 'sieveSslMode' => 'tls',
- ])
+ $this->provisioningManager->getConfigs()
);
return new TemplateResponse(Application::APP_ID, 'settings-admin');
diff --git a/src/components/settings/AdminSettings.vue b/src/components/settings/AdminSettings.vue
index e93acd457..dd5641d79 100644
--- a/src/components/settings/AdminSettings.vue
+++ b/src/components/settings/AdminSettings.vue
@@ -20,34 +20,212 @@
-->
<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>
+ <SettingsSection
+ :title="t( 'mail', 'Mail app')"
+ :description="t( 'mail', 'The mail app allows users to read mails on their IMAP accounts.')">
+ <p>
{{
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>
+ </p>
+ <div class="ap-description">
+ <h3>Account provisioning</h3>
+ <article>
+ <p>
+ {{
+ t(
+ 'mail',
+ 'A provisioning configuration will provision all accounts with a matching email address.'
+ )
+ }}
+ {{
+ t(
+ 'mail',
+ 'Using the wildcard (*) in the provisioning domain field will create a configuration that applies to all users, provided they do not match another configuration.'
+ )
+ }}
+ <br>
+ {{
+ t(
+ 'mail',
+ 'The provisioning mechanism will prioritise specific domain configurations over the wildcard domain configuration.'
+ )
+ }}
+ {{
+ t(
+ 'mail',
+ 'Should a new matching configuration be found after the user was already provisioned with another configuration, the new configuration will take precedence and the user will be reprovisioned with the configuration.'
+ )
+ }}
+ <br>
+ {{
+ t(
+ 'mail',
+ 'There can only be one configuartion per domain, and only one wildcard domain configuration.'
+ )
+ }}
+ <br>
+ {{
+ t(
+ 'mail',
+ 'These settings can be used in conjuction with each other.'
+ )
+ }}
+ <br>
+ {{
+ t(
+ 'mail',
+ 'If you only want to provision one domain for all users, use the wildcard (*).'
+ )
+ }}
+ <br>
+ {{
+ 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>
+ </article>
+ </div>
+ <h3>Provisioning Configurations</h3>
+ <p>
+ <button class="config-button icon-add" @click="addNew=true">
+ {{ t('mail', 'Add new config') }}
+ </button>
+ <button class="config-button icon-settings" @click="provisionAll">
+ {{ t('mail', 'Provision all accounts') }}
+ </button>
+ <ProvisioningSettings v-if="addNew"
+ :key="formKey"
+ :setting="preview"
+ :submit="saveNewSettings"
+ :delete-button="false" />
+ <ProvisioningSettings v-for="setting in configs"
+ :id="setting.id"
+ :key="setting.id"
+ :setting="setting"
+ :submit="saveSettings"
+ :disable="deleteProvisioning" />
+ </p>
+ </SettingsSection>
</template>
<script>
+import logger from '../../logger'
+import { showError, showSuccess } from '@nextcloud/dialogs'
import ProvisioningSettings from './ProvisioningSettings'
+import SettingsSection from '@nextcloud/vue/dist/Components/SettingsSection'
+import {
+ disableProvisioning,
+ createProvisioningSettings,
+ updateProvisioningSettings,
+ provisionAll,
+} from '../../service/SettingsService'
export default {
name: 'AdminSettings',
components: {
ProvisioningSettings,
+ SettingsSection,
},
props: {
provisioningSettings: {
- type: Object,
+ type: Array,
required: true,
},
},
+ data() {
+ return {
+ addNew: false,
+ formKey: Math.random(),
+ configs: this.provisioningSettings,
+ preview: {
+ provisioningDomain: '',
+ emailTemplate: '',
+ imapHost: 'mx.domain.com',
+ imapPort: 993,
+ imapUser: '%USERID%domain.com',
+ imapSslMode: 'ssl',
+ smtpHost: 'mx.domain.com',
+ smtpPort: 587,
+ smtpUser: '%USERID%domain.com',
+ smtpSslMode: 'tls',
+ previewData1: {
+ uid: 'user123',
+ email: '',
+ },
+ previewData2: {
+ uid: 'user321',
+ email: 'user@domain.com',
+ },
+ loading: false,
+ },
+ }
+ },
+ methods: {
+ async saveSettings(settings) {
+ try {
+ await updateProvisioningSettings(settings)
+ showSuccess(t('mail', 'Successfully updated config for "{domain}"', { domain: settings.provisioningDomain }))
+ } catch (error) {
+ showError(t('mail', 'Error saving config'))
+ logger.error('Could not save provisioning setting', { error })
+ }
+ },
+ async saveNewSettings(settings) {
+ try {
+ await createProvisioningSettings(settings)
+ this.configs.unshift(settings)
+ this.addNew = false
+ this.resetForm()
+ showSuccess(t('mail', 'Saved config for "{domain}"', { domain: settings.provisioningDomain }))
+ } catch (error) {
+ showError(t('mail', 'Could not save provisioning setting'))
+ logger.error('Could not save provisioning setting', { error })
+ }
+
+ },
+ resetForm() {
+ this.formKey = Math.random()
+ },
+ async provisionAll() {
+ try {
+ const count = await provisionAll()
+ showSuccess(t('mail', 'Successfully provisioned {count} accounts.', { count: count.count }))
+
+ } catch (error) {
+ showError(t('mail', 'There was an error when provisioning accounts.'))
+ logger.error('Could not provision accounts', { error })
+ }
+ },
+ async deleteProvisioning(id) {
+ const deleted = this.configs.find(c => c.id === id)
+ try {
+ await disableProvisioning(id)
+ logger.info('deprovisioned successfully')
+ this.configs = this.configs.filter(c => c.id !== id)
+ showSuccess(t('mail', 'Sucessfully deleted and deprovisioned accounts for "{domain}"', { domain: deleted.provisioningDomain }))
+ } catch (error) {
+ showError(t('mail', 'Error when deleting and deprovisioning accounts for "{domain}"', { domain: deleted.provisioningDomain }))
+ logger.error('Could not delete provisioning config', { error })
+ }
+ },
+ },
}
</script>
+<style lang="scss" scoped>
+ .ap-description {
+ margin-bottom: 24px;
+ }
+ .config-button {
+ line-height: 24px;
+ padding-left: 48px;
+ padding-top: 6px;
+ padding-bottom: 6px;
+ background-position: 24px;
+ }
+</style>
diff --git a/src/components/settings/ProvisionPreview.vue b/src/components/settings/ProvisionPreview.vue
index 8d562e404..1c75be12b 100644
--- a/src/components/settings/ProvisionPreview.vue
+++ b/src/components/settings/ProvisionPreview.vue
@@ -26,6 +26,8 @@
<span v-if="data.email">email={{ email }}</span>
</b>
<br>
+ {{ t('mail', 'Domain Match: {provisioningDomain}', {provisioningDomain}) }}
+ <br>
{{ t('mail', 'Email: {email}', {email}) }}<br>
{{
t('mail', 'IMAP: {user} on {host}:{port} ({ssl} encryption)', {
@@ -73,6 +75,9 @@ export default {
email() {
return this.templates.email.replace('%USERID%', this.data.uid).replace('%EMAIL%', this.data.email)
},
+ provisioningDomain() {
+ return this.templates.provisioningDomain
+ },
imapHost() {
return this.templates.imapHost
},
diff --git a/src/components/settings/ProvisioningSettings.vue b/src/components/settings/ProvisioningSettings.vue
index 5d6a14d07..9b963940d 100644
--- a/src/components/settings/ProvisioningSettings.vue
+++ b/src/components/settings/ProvisioningSettings.vue
@@ -20,45 +20,32 @@
-->
<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="section">
+ <h4>{{ t('mail','Configuration for "{provisioningDomain}"', {provisioningDomain}) }}</h4>
+ <div class="form-preview-row">
+ <form :id="'prov-form-' + setting.id" @submit.prevent="submitForm">
<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>
+ <label :for="'mail-provision-domain' + setting.id"> {{ t('mail', 'Provisioning domain') }}* </label>
+ <br>
+ <input
+ :id="'mail-provision-domain' + setting.id"
+ v-model="provisioningDomain"
+ :disabled="loading"
+ name="provisioningDomain"
+ type="text">
+ <br>
+ <label :for="'mail-provision-email' + setting.id"> {{ t('mail', 'Email address template') }}* </label>
<br>
<input
- id="mail-provision-email"
+ :id="'mail-provision-email' + setting.id"
v-model="emailTemplate"
:disabled="loading"
- name="email"
+ name="emailTemplate"
type="text">
</div>
</div>
@@ -67,32 +54,32 @@
{{ t('mail', 'IMAP') }}
</div>
<div class="group-inputs">
- <label for="mail-provision-imap-user">
+ <label :for="'mail-provision-imap-user' + setting.id">
{{ t('mail', 'User') }}*
<br>
<input
- id="mail-provision-imap-user"
+ :id="'mail-provision-imap-user' + setting.id"
v-model="imapUser"
:disabled="loading"
name="email"
type="text">
</label>
<div class="flex-row">
- <label for="mail-provision-imap-host">
+ <label :for="'mail-provision-imap-host' + setting.id">
{{ t('mail', 'Host') }}
<br>
<input
- id="mail-provision-imap-host"
+ :id="'mail-provision-imap-host' + setting.id"
v-model="imapHost"
:disabled="loading"
name="email"
type="text">
</label>
- <label for="mail-provision-imap-port">
+ <label :for="'mail-provision-imap-port' + setting.id">
{{ t('mail', 'Port') }}
<br>
<input
- id="mail-provision-imap-port"
+ :id="'mail-provision-imap-port' + setting.id"
v-model="imapPort"
:disabled="loading"
name="email"
@@ -101,7 +88,7 @@
</div>
<div class="flex-row">
<input
- id="mail-provision-imap-user-none"
+ :id="'mail-provision-imap-user-none' + setting.id"
v-model="imapSslMode"
type="radio"
name="man-imap-sec"
@@ -109,10 +96,10 @@
value="none">
<label
class="button"
- for="mail-provision-imap-user-none"
+ :for="'mail-provision-imap-user-none' + setting.id"
:class="{primary: imapSslMode === 'none'}">{{ t('mail', 'None') }}</label>
<input
- id="mail-provision-imap-user-ssl"
+ :id="'mail-provision-imap-user-ssl' + setting.id"
v-model="imapSslMode"
type="radio"
name="man-imap-sec"
@@ -120,10 +107,10 @@
value="ssl">
<label
class="button"
- for="mail-provision-imap-user-ssl"
+ :for="'mail-provision-imap-user-ssl' + setting.id"
:class="{primary: imapSslMode === 'ssl'}">{{ t('mail', 'SSL/TLS') }}</label>
<input
- id="mail-provision-imap-user-tls"
+ :id="'mail-provision-imap-user-tls' + setting.id"
v-model="imapSslMode"
type="radio"
name="man-imap-sec"
@@ -131,7 +118,7 @@
value="tls">
<label
class="button"
- for="mail-provision-imap-user-tls"
+ :for="'mail-provision-imap-user-tls' + setting.id"
:class="{primary: imapSslMode === 'tls'}">{{ t('mail', 'STARTTLS') }}</label>
</div>
</div>
@@ -141,32 +128,32 @@
{{ t('mail', 'SMTP') }}
</div>
<div class="group-inputs">
- <label for="mail-provision-smtp-user">
+ <label :for="'mail-provision-smtp-user' + setting.id">
{{ t('mail', 'User') }}*
<br>
<input
- id="mail-provision-smtp-user"
+ :id="'mail-provision-smtp-user' + setting.id"
v-model="smtpUser"
:disabled="loading"
name="email"
type="text">
</label>
<div class="flex-row">
- <label for="mail-provision-smtp-host">
+ <label :for="'mail-provision-smtp-host' + setting.id">
{{ t('mail', 'Host') }}
<br>
<input
- id="mail-provision-smtp-host"
+ :id="'mail-provision-smtp-host' + setting.id"
v-model="smtpHost"
:disabled="loading"
name="email"
type="text">
</label>
- <label for="mail-provision-smtp-port">
+ <label :for="'mail-provision-smtp-port' + setting.id">
{{ t('mail', 'Port') }}
<br>
<input
- id="mail-provision-smtp-port"
+ :id="'mail-provision-smtp-port' + setting.id"
v-model="smtpPort"
:disabled="loading"
name="email"
@@ -175,7 +162,7 @@
</div>
<div class="flex-row">
<input
- id="mail-provision-smtp-user-none"
+ :id="'mail-provision-smtp-user-none' + setting.id"
v-model="smtpSslMode"
type="radio"
name="man-smtp-sec"
@@ -183,10 +170,10 @@
value="none">
<label
class="button"
- for="mail-provision-smtp-user-none"
+ :for="'mail-provision-smtp-user-none' + setting.id"
:class="{primary: smtpSslMode === 'none'}">{{ t('mail', 'None') }}</label>
<input
- id="mail-provision-smtp-user-ssl"
+ :id="'mail-provision-smtp-user-ssl' + setting.id"
v-model="smtpSslMode"
type="radio"
name="man-smtp-sec"
@@ -194,10 +181,10 @@
value="ssl">
<label
class="button"
- for="mail-provision-smtp-user-ssl"
+ :for="'mail-provision-smtp-user-ssl' + setting.id"
:class="{primary: smtpSslMode === 'ssl'}">{{ t('mail', 'SSL/TLS') }}</label>
<input
- id="mail-provision-smtp-user-tls"
+ :id="'mail-provision-smtp-user-tls' + setting.id"
v-model="smtpSslMode"
type="radio"
name="man-smtp-sec"
@@ -205,7 +192,7 @@
value="tls">
<label
class="button"
- for="mail-provision-smtp-user-tls"
+ :for="'mail-provision-smtp-user-tls' + setting.id"
:class="{primary: smtpSslMode === 'tls'}">{{ t('mail', 'STARTTLS') }}</label>
</div>
</div>
@@ -216,40 +203,41 @@
</div>
<div class="group-inputs">
<div>
- <input id="mail-provision-sieve-enabled"
+ <input
+ :id="'mail-provision-sieve-enabled' + setting.id"
v-model="sieveEnabled"
type="checkbox"
class="checkbox">
- <label for="mail-provision-sieve-enabled">
+ <label :for="'mail-provision-sieve-enabled' + setting.id">
{{ t('mail', 'Enable sieve integration') }}
</label>
</div>
- <label for="mail-provision-sieve-user">
+ <label :for="'mail-provision-sieve-user' + setting.id">
{{ t('mail', 'User') }}*
<br>
<input
- id="mail-provision-sieve-user"
+ :id="'mail-provision-sieve-user' + setting.id"
v-model="sieveUser"
:disabled="loading"
name="email"
type="text">
</label>
<div class="flex-row">
- <label for="mail-provision-sieve-host">
+ <label :for="'mail-provision-sieve-host' + setting.id">
{{ t('mail', 'Host') }}
<br>
<input
- id="mail-provision-sieve-host"
+ :id="'mail-provision-sieve-host' + setting.id"
v-model="sieveHost"
:disabled="loading"
name="email"
type="text">
</label>
- <label for="mail-provision-sieve-port">
+ <label :for="'mail-provision-sieve-port' + setting.id">
{{ t('mail', 'Port') }}
<br>
<input
- id="mail-provision-sieve-port"
+ :id="'mail-provision-sieve-port' + setting.id"
v-model="sievePort"
:disabled="loading"
name="email"
@@ -258,7 +246,7 @@
</div>
<div class="flex-row">
<input
- id="mail-provision-sieve-user-none"
+ :id="'mail-provision-sieve-user-none' + setting.id"
v-model="sieveSslMode"
type="radio"
name="man-sieve-sec"
@@ -266,10 +254,10 @@
value="none">
<label
class="button"
- for="mail-provision-sieve-user-none"
+ :for="'mail-provision-sieve-user-none' + setting.id"
:class="{primary: sieveSslMode === 'none'}">{{ t('mail', 'None') }}</label>
<input
- id="mail-provision-sieve-user-ssl"
+ :id="'mail-provision-sieve-user-ssl' + setting.id"
v-model="sieveSslMode"
type="radio"
name="man-sieve-sec"
@@ -277,10 +265,10 @@
value="ssl">
<label
class="button"
- for="mail-provision-sieve-user-ssl"
+ :for="'mail-provision-sieve-user-ssl' + setting.id"
:class="{primary: sieveSslMode === 'ssl'}">{{ t('mail', 'SSL/TLS') }}</label>
<input
- id="mail-provision-sieve-user-tls"
+ :id="'mail-provision-sieve-user-tls' + setting.id"
v-model="sieveSslMode"
type="radio"
name="man-sieve-sec"
@@ -288,7 +276,7 @@
value="tls">
<label
class="button"
- for="mail-provision-sieve-user-tls"
+ :for="'mail-provision-sieve-user-tls' + setting.id"
:class="{primary: sieveSslMode === 'tls'}">{{ t('mail', 'STARTTLS') }}</label>
</div>
</div>
@@ -297,15 +285,17 @@
<div class="group-title" />
<div class="group-inputs">
<input
+ class="button config-button icon-upload"
type="submit"
- class="primary"
:disabled="loading"
- :value="t('mail', 'Apply and create/update for all users')">
+ :value="t('mail', 'Save Config')">
<input
+ v-if="deleteButton"
type="button"
+ class="button config-button icon-delete"
:disabled="loading"
- :value="t('mail', 'Disable and un-provision existing accounts')"
- @click="disable">
+ :value="t('mail', 'Unprovision & Delete Config')"
+ @click="disableConfig()">
<br>
<small>{{
t('mail', "* %USERID% and %EMAIL% will be replaced with the user's UID and email")
@@ -328,38 +318,53 @@
</div>
</div>
</template>
-
<script>
import logger from '../../logger'
import ProvisionPreview from './ProvisionPreview'
-import { disableProvisioning, saveProvisioningSettings } from '../../service/SettingsService'
export default {
name: 'ProvisioningSettings',
- components: { ProvisionPreview },
+ components: {
+ ProvisionPreview,
+ },
props: {
- settings: {
+ setting: {
type: Object,
required: true,
},
+ submit: {
+ type: Function,
+ required: true,
+ },
+ disable: {
+ type: Function,
+ required: false,
+ default: undefined,
+ },
+ deleteButton: {
+ type: Boolean,
+ required: false,
+ default: 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',
- sieveEnabled: this.settings.sieveEnabled,
- sieveHost: this.settings.sieveHost,
- sievePort: this.settings.sievePort,
- sieveSslMode: this.settings.sieveSslMode,
- sieveUser: this.settings.sieveUser,
+ active: !!this.setting.active,
+ provisioningDomain: this.setting.provisioningDomain || '',
+ emailTemplate: this.setting.emailTemplate || '',
+ imapHost: this.setting.imapHost || 'mx.domain.com',
+ imapPort: this.setting.imapPort || 993,
+ imapUser: this.setting.imapUser || '%USERID%domain.com',
+ imapSslMode: this.setting.imapSslMode || 'ssl',
+ smtpHost: this.setting.smtpHost || 'mx.domain.com',
+ smtpPort: this.setting.smtpPort || 587,
+ smtpUser: this.setting.smtpUser || '%USERID%domain.com',
+ smtpSslMode: this.setting.smtpSslMode || 'tls',
+ sieveEnabled: this.setting.sieveEnabled || '',
+ sieveHost: this.setting.sieveHost || '',
+ sievePort: this.setting.sievePort || '',
+ sieveSslMode: this.setting.sieveSslMode || '',
+ sieveUser: this.setting.sieveUser || '',
previewData1: {
uid: 'user123',
email: '',
@@ -375,6 +380,7 @@ export default {
previewTemplates() {
return {
email: this.emailTemplate,
+ provisioningDomain: this.provisioningDomain,
imapUser: this.imapUser,
imapHost: this.imapHost,
imapPort: this.imapPort,
@@ -392,53 +398,49 @@ export default {
},
},
beforeMount() {
- logger.debug('provisioning settings loaded', { settings: this.settings })
+ logger.debug('provisioning setting loaded', { setting: this.setting })
},
methods: {
- submit() {
+ async submitForm() {
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,
- sieveEnabled: this.sieveEnabled,
- sieveUser: this.sieveUser,
- sieveHost: this.sieveHost,
- sievePort: this.sievePort,
- sieveSslMode: this.sieveSslMode,
- })
- .then(() => {
- logger.info('provisioning settings updated')
- })
- .catch((error) => {
- // TODO: show user feedback
- logger.error('Could not save provisioning settings', { error })
- })
- .then(() => {
- this.loading = false
+ try {
+ await this.submit({
+ id: this.setting.id || null,
+ active: this.setting.active || true,
+ emailTemplate: this.emailTemplate,
+ provisioningDomain: this.provisioningDomain,
+ imapUser: this.imapUser,
+ imapHost: this.imapHost,
+ imapPort: this.imapPort,
+ imapSslMode: this.imapSslMode,
+ smtpUser: this.smtpUser,
+ smtpHost: this.smtpHost,
+ smtpPort: this.smtpPort,
+ smtpSslMode: this.smtpSslMode,
+ sieveEnabled: this.sieveEnabled,
+ sieveUser: this.sieveUser,
+ sieveHost: this.sieveHost,
+ sievePort: this.sievePort,
+ sieveSslMode: this.sieveSslMode,
})
+
+ logger.info('provisioning setting updated')
+ } catch (error) {
+ logger.error('Could not save provisioning setting', { error })
+ } finally {
+ this.loading = false
+ }
},
- disable() {
+ async disableConfig() {
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
- })
+ try {
+ await this.disable(this.setting.id)
+ } catch (error) {
+ logger.error('Could not delete provisioning setting', { error })
+ } finally {
+ this.loading = false
+ }
},
},
}
@@ -447,8 +449,6 @@ export default {
<style lang="scss" scoped>
.form-preview-row {
display: flex;
- flex-direction: row;
- flex-wrap: wrap;
div:last-child {
margin-top: 10px;
@@ -473,6 +473,13 @@ export default {
input[type='text'] {
min-width: 200px;
}
+ .config-button {
+ line-height: 24px;
+ padding-left: 48px;
+ padding-top: 6px;
+ padding-bottom: 6px;
+ background-position: 24px;
+ }
}
}
@@ -499,7 +506,6 @@ input[type='radio'] {
.flex-row {
display: flex;
}
-
form {
label {
color: var(--color-text-maxcontrast);
diff --git a/src/main-settings.js b/src/main-settings.js
index a30e72601..998474ac5 100644
--- a/src/main-settings.js
+++ b/src/main-settings.js
@@ -22,6 +22,7 @@
import { generateFilePath } from '@nextcloud/router'
import { getRequestToken } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
+import '@nextcloud/dialogs/styles/toast.scss'
import Vue from 'vue'
import AdminSettings from './components/settings/AdminSettings'
@@ -37,6 +38,6 @@ Vue.mixin(Nextcloud)
const View = Vue.extend(AdminSettings)
new View({
propsData: {
- provisioningSettings: loadState('mail', 'provisioning_settings') || {},
+ provisioningSettings: loadState('mail', 'provisioning_settings') || [],
},
}).$mount('#mail-admin-settings')
diff --git a/src/service/SettingsService.js b/src/service/SettingsService.js
index 926a35052..73cfd3f42 100644
--- a/src/service/SettingsService.js
+++ b/src/service/SettingsService.js
@@ -22,14 +22,39 @@
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
-export const saveProvisioningSettings = (config) => {
+export const getProvisioningSettings = (config) => {
const url = generateUrl('/apps/mail/api/settings/provisioning')
- return axios.post(url, config).then((resp) => resp.data)
+ return axios.get(url, config).then((resp) => resp.data)
}
-export const disableProvisioning = () => {
+export const provisionAll = () => {
+ const url = generateUrl('/apps/mail/api/settings/provisioning/all')
+
+ return axios.put(url).then((resp) => resp.data)
+}
+
+export const createProvisioningSettings = (config) => {
const url = generateUrl('/apps/mail/api/settings/provisioning')
+ const data = {
+ data: config,
+ }
+ return axios.post(url, data).then((resp) => resp.data)
+}
+
+export const updateProvisioningSettings = (config) => {
+ const url = generateUrl('/apps/mail/api/settings/provisioning/{id}', {
+ id: config.id,
+ })
+ const data = {
+ data: config,
+ }
+ return axios.post(url, data).then((resp) => resp.data)
+}
+export const disableProvisioning = (id) => {
+ const url = generateUrl('/apps/mail/api/settings/provisioning/{id}', {
+ id,
+ })
return axios.delete(url).then((resp) => resp.data)
}
diff --git a/tests/Integration/Db/MailAccountMapperTest.php b/tests/Integration/Db/MailAccountMapperTest.php
index 9dc9b5021..7dc69b580 100644
--- a/tests/Integration/Db/MailAccountMapperTest.php
+++ b/tests/Integration/Db/MailAccountMapperTest.php
@@ -68,7 +68,7 @@ class MailAccountMapperTest extends TestCase {
$this->account->setOutboundSslMode('ssl');
$this->account->setUserId('user12345');
$this->account->setEditorMode('plaintext');
- $this->account->setProvisioned(false);
+ $this->account->setProvisioningId(null);
$this->account->setOrder(27);
}
diff --git a/tests/Integration/Db/MailAccountTest.php b/tests/Integration/Db/MailAccountTest.php
index 8db2729f8..7eea6142a 100644
--- a/tests/Integration/Db/MailAccountTest.php
+++ b/tests/Integration/Db/MailAccountTest.php
@@ -44,7 +44,7 @@ class MailAccountTest extends TestCase {
$a->setOutboundPassword('xxxx');
$a->setOutboundSslMode('ssl');
$a->setEditorMode('html');
- $a->setProvisioned(false);
+ $a->setProvisioningId(null);
$a->setOrder(13);
$this->assertEquals([
@@ -62,7 +62,7 @@ class MailAccountTest extends TestCase {
'smtpSslMode' => 'ssl',
'signature' => null,
'editorMode' => 'html',
- 'provisioned' => false,
+ 'provisioningId' => null,
'order' => 13,
'showSubscribedOnly' => null,
'personalNamespace' => null,
@@ -90,15 +90,15 @@ class MailAccountTest extends TestCase {
'smtpSslMode' => 'ssl',
'signature' => null,
'editorMode' => null,
- 'provisioned' => false,
+ 'provisioningId' => null,
'order' => null,
- 'showSubscribedOnly' => null,
+ 'showSubscribedOnly' => false,
'personalNamespace' => null,
'draftsMailboxId' => null,
'sentMailboxId' => null,
'trashMailboxId' => null,
'sieveEnabled' => false,
- 'signatureAboveQuote' => false,
+ 'signatureAboveQuote' => false
];
$a = new MailAccount($expected);
// TODO: fix inconsistency
diff --git a/tests/Integration/Db/ProvisioningMapperTest.php b/tests/Integration/Db/ProvisioningMapperTest.php
new file mode 100644
index 000000000..6ed040f04
--- /dev/null
+++ b/tests/Integration/Db/ProvisioningMapperTest.php
@@ -0,0 +1,198 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Anna Larch <anna.larch@nextcloud.com>
+ *
+ * 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\Integration\Db;
+
+use OC;
+use ChristophWurst\Nextcloud\Testing\DatabaseTransaction;
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use OCA\Mail\Db\Provisioning;
+use OCA\Mail\Db\ProvisioningMapper;
+use OCA\Mail\Exception\ValidationException;
+use OCP\IDBConnection;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @group DB
+ */
+class ProvisioningMapperTest extends TestCase {
+ use DatabaseTransaction;
+
+ /** @var ProvisioningMapper */
+ private $mapper;
+
+ /** @var IDBConnection */
+ private $db;
+
+ /** @var MockObject */
+ private $logger;
+
+ /** @var Alias */
+ private $alias;
+
+ /** @var [] */
+ public $data = [];
+
+ /**
+ * Initialize Mapper
+ */
+ public function setup(): void {
+ parent::setUp();
+ $this->db = OC::$server->getDatabaseConnection();
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->mapper = new ProvisioningMapper($this->db, $this->logger);
+ $this->data['provisioningDomain'] = 'heart-of-gold.com' ;
+ $this->data['emailTemplate'] = '%USERID%@heart-of-gold.com';
+ $this->data['imapUser'] = 'marvin@heart-of-gold.com';
+ $this->data['imapHost'] = 'imap.heart-of-gold.com';
+ $this->data['imapPort'] = '42';
+ $this->data['imapSslMode'] = 'none';
+ $this->data['smtpUser'] = 'trillian@heart-of-gold.com';
+ $this->data['smtpHost'] = 'smtp.heart-of-gold.com';
+ $this->data['smtpPort'] = 24;
+ $this->data['smtpSslMode'] = 'none';
+ $this->data['sieveEnabled'] = false;
+ }
+
+ public function testValidate() {
+ $provisioning = new Provisioning();
+ $provisioning->setId(1);
+ $provisioning->setProvisioningDomain($this->data['provisioningDomain']);
+ $provisioning->setEmailTemplate($this->data['emailTemplate']);
+ $provisioning->setImapUser($this->data['imapUser']);
+ $provisioning->setImapHost($this->data['imapHost']);
+ $provisioning->setImapPort(42);
+ $provisioning->setImapSslMode($this->data['imapSslMode']);
+ $provisioning->setSmtpUser($this->data['smtpUser']);
+ $provisioning->setSmtpHost($this->data['smtpHost']);
+ $provisioning->setSmtpPort(24);
+ $provisioning->setSmtpSslMode($this->data['smtpSslMode']);
+ $provisioning->setSieveEnabled($this->data['sieveEnabled']);
+
+ $provisioning = $this->mapper->validate($this->data);
+
+ $this->assertInstanceOf(Provisioning::class, $provisioning);
+ foreach ($this->data as $key => $value) {
+ $getter = 'get' . ucfirst($key);
+ if ($key === 'imapPort' || $key === 'smtpPort') {
+ $this->assertIsInt($provisioning->$getter());
+ $this->assertEquals($provisioning->$getter(), (int)$value);
+ } else {
+ $this->assertEquals($provisioning->$getter(), $value);
+ }
+ }
+ }
+
+ public function testValidateException() {
+ $data = [];
+ $data['provisioningDomain'] = 'heart-of-gold.com' ;
+
+ $this->expectException(ValidationException::class);
+
+ $provisioning = $this->mapper->validate($data);
+ }
+
+ public function testGetNoResult() {
+ $db = $this->mapper->get(99999);
+ $this->assertNull($db);
+ }
+
+ /**
+ * @return void
+ */
+ public function testUpdate() {
+ $provisioning = new Provisioning();
+ $provisioning->setProvisioningDomain($this->data['provisioningDomain']);
+ $provisioning->setEmailTemplate($this->data['emailTemplate']);
+ $provisioning->setImapUser($this->data['imapUser']);
+ $provisioning->setImapHost($this->data['imapHost']);
+ $provisioning->setImapPort(42);
+ $provisioning->setImapSslMode($this->data['imapSslMode']);
+ $provisioning->setSmtpUser($this->data['smtpUser']);
+ $provisioning->setSmtpHost($this->data['smtpHost']);
+ $provisioning->setSmtpPort(24);
+ $provisioning->setSmtpSslMode($this->data['smtpSslMode']);
+ $provisioning->setSieveEnabled($this->data['sieveEnabled']);
+ $provisioning = $this->mapper->insert($provisioning);
+ $id = $provisioning->getId();
+ $provisioning->setProvisioningDomain('arthur-dent.com');
+
+ $update = $this->mapper->update($provisioning);
+
+ $this->assertInstanceOf(Provisioning::class, $update);
+ $this->assertEquals($id, $update->getId());
+ $this->assertEquals('arthur-dent.com', $update->getProvisioningDomain());
+ }
+
+ public function testGetAll() {
+ $provisioning = new Provisioning();
+ $provisioning->setProvisioningDomain($this->data['provisioningDomain']);
+ $provisioning->setEmailTemplate($this->data['emailTemplate']);
+ $provisioning->setImapUser($this->data['imapUser']);
+ $provisioning->setImapHost($this->data['imapHost']);
+ $provisioning->setImapPort(42);
+ $provisioning->setImapSslMode($this->data['imapSslMode']);
+ $provisioning->setSmtpUser($this->data['smtpUser']);
+ $provisioning->setSmtpHost($this->data['smtpHost']);
+ $provisioning->setSmtpPort(24);
+ $provisioning->setSmtpSslMode($this->data['smtpSslMode']);
+ $provisioning->setSieveEnabled($this->data['sieveEnabled']);
+ $provisioning = $this->mapper->insert($provisioning);
+
+ $results = $this->mapper->getAll();
+
+ $this->assertIsArray($results);
+ $this->assertNotEmpty($results);
+ foreach ($results as $result) {
+ $this->assertInstanceOf(Provisioning::class, $result);
+ }
+ }
+
+ public function testGet() {
+ $provisioning = new Provisioning();
+ $provisioning->setProvisioningDomain($this->data['provisioningDomain']);
+ $provisioning->setEmailTemplate($this->data['emailTemplate']);
+ $provisioning->setImapUser($this->data['imapUser']);
+ $provisioning->setImapHost($this->data['imapHost']);
+ $provisioning->setImapPort(42);
+ $provisioning->setImapSslMode($this->data['imapSslMode']);
+ $provisioning->setSmtpUser($this->data['smtpUser']);
+ $provisioning->setSmtpHost($this->data['smtpHost']);
+ $provisioning->setSmtpPort(24);
+ $provisioning->setSmtpSslMode($this->data['smtpSslMode']);
+ $provisioning->setSieveEnabled($this->data['sieveEnabled']);
+ $provisioning = $this->mapper->insert($provisioning);
+
+ $db = $this->mapper->get($provisioning->id);
+
+ $this->assertInstanceOf(Provisioning::class, $db);
+ foreach ($this->data as $key => $value) {
+ $getter = 'get' . ucfirst($key);
+ if ($key === 'imapPort' || $key === 'smtpPort') {
+ $this->assertEquals($db->$getter(), (int)$value);
+ } else {
+ $this->assertEquals($db->$getter(), $value);
+ }
+ }
+ }
+}
diff --git a/tests/Unit/Controller/SettingsControllerTest.php b/tests/Unit/Controller/SettingsControllerTest.php
index c19b459ca..5d1947459 100644
--- a/tests/Unit/Controller/SettingsControllerTest.php
+++ b/tests/Unit/Controller/SettingsControllerTest.php
@@ -27,6 +27,7 @@ namespace OCA\Mail\Tests\Unit\Controller;
use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
use OCA\Mail\Controller\SettingsController;
+use OCA\Mail\Db\Provisioning;
use OCA\Mail\Tests\Integration\TestCase;
use OCP\AppFramework\Http\JSONResponse;
@@ -48,50 +49,25 @@ class SettingsControllerTest extends TestCase {
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',
- false,
- '',
- '',
- 0,
- ''
- );
+ ->method('provision')
+ ->with();
- $response = $this->controller->provisioning(
- '%USERID%@domain.com',
- '%USERID%@domain.com',
- 'mx.domain.com',
- 993,
- 'ssl',
- '%USERID%@domain.com',
- 'mx.domain.com',
- 567,
- 'tls',
- false,
- '',
- '',
- 0,
- ''
- );
+ $response = $this->controller->provision();
$this->assertInstanceOf(JSONResponse::class, $response);
}
public function testDeprovision() {
+ $provisioning = new Provisioning();
$this->mock->getParameter('provisioningManager')
->expects($this->once())
- ->method('deprovision');
-
- $response = $this->controller->deprovision();
+ ->method('getConfigById')
+ ->willReturn($provisioning);
+ $this->mock->getParameter('provisioningManager')
+ ->expects($this->once())
+ ->method('deprovision')
+ ->with($provisioning);
+ $response = $this->controller->deprovision(1);
$this->assertInstanceOf(JSONResponse::class, $response);
}
diff --git a/tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php b/tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php
index d8d4eaf8c..97425c908 100644
--- a/tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php
+++ b/tests/Unit/Http/Middleware/ProvisioningMiddlewareTest.php
@@ -27,8 +27,8 @@ namespace OCA\Mail\Tests\Unit\Http\Middleware;
use ChristophWurst\Nextcloud\Testing\TestCase;
use OCA\Mail\Controller\PageController;
+use OCA\Mail\Db\Provisioning;
use OCA\Mail\Http\Middleware\ProvisioningMiddleware;
-use OCA\Mail\Service\Provisioning\Config;
use OCA\Mail\Service\Provisioning\Manager;
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
use OCP\Authentication\Exceptions\PasswordUnavailableException;
@@ -85,17 +85,19 @@ class ProvisioningMiddlewareTest extends TestCase {
}
public function testBeforeControllerNoCredentialsAvailable() {
- $user = $this->createMock(IUser::class);
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
$this->userSession->expects($this->once())
->method('getUser')
->willReturn($user);
- $config = $this->createMock(Config::class);
+ $configs = [new Provisioning()];
$this->provisioningManager->expects($this->once())
- ->method('getConfig')
- ->willReturn($config);
- $config->expects($this->once())
- ->method('isActive')
- ->willReturn(true);
+ ->method('getConfigs')
+ ->willReturn($configs);
+ $this->provisioningManager->expects($this->once())
+ ->method('provisionSingleUser')
+ ->with($configs, $user);
$this->credentialStore->expects($this->once())
->method('getLoginCredentials')
->willThrowException($this->createMock(CredentialsUnavailableException::class));
@@ -109,17 +111,19 @@ class ProvisioningMiddlewareTest extends TestCase {
}
public function testBeforeControllerNoPasswordAvailable() {
- $user = $this->createMock(IUser::class);
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
$this->userSession->expects($this->once())
->method('getUser')
->willReturn($user);
- $config = $this->createMock(Config::class);
+ $configs = [new Provisioning()];
+ $this->provisioningManager->expects($this->once())
+ ->method('getConfigs')
+ ->willReturn($configs);
$this->provisioningManager->expects($this->once())
- ->method('getConfig')
- ->willReturn($config);
- $config->expects($this->once())
- ->method('isActive')
- ->willReturn(true);
+ ->method('provisionSingleUser')
+ ->with($configs, $user);
$credentials = $this->createMock(ICredentials::class);
$this->credentialStore->expects($this->once())
->method('getLoginCredentials')
@@ -137,36 +141,15 @@ class ProvisioningMiddlewareTest extends TestCase {
}
public function testBeforeControllerNoConfigAvailable() {
- $user = $this->createMock(IUser::class);
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
$this->userSession->expects($this->once())
->method('getUser')
->willReturn($user);
- $this->provisioningManager->expects($this->once())
- ->method('getConfig')
- ->willReturn(null);
- $this->credentialStore->expects($this->never())
- ->method('getLoginCredentials');
- $this->provisioningManager->expects($this->never())
- ->method('updatePassword');
-
- $this->middleware->beforeController(
- $this->createMock(PageController::class),
- 'index'
- );
- }
-
- public function testBeforeControllerNotActive() {
- $user = $this->createMock(IUser::class);
- $this->userSession->expects($this->once())
- ->method('getUser')
- ->willReturn($user);
- $config = $this->createMock(Config::class);
- $this->provisioningManager->expects($this->once())
- ->method('getConfig')
- ->willReturn($config);
- $config->expects($this->once())
- ->method('isActive')
- ->willReturn(false);
+ $this->provisioningManager->expects($this->any())
+ ->method('getConfigs')
+ ->willReturn([]);
$this->credentialStore->expects($this->never())
->method('getLoginCredentials');
$this->provisioningManager->expects($this->never())
@@ -179,17 +162,21 @@ class ProvisioningMiddlewareTest extends TestCase {
}
public function testBeforeController() {
- $user = $this->createMock(IUser::class);
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
$this->userSession->expects($this->once())
->method('getUser')
->willReturn($user);
- $config = $this->createMock(Config::class);
+ $config = new Provisioning();
+ $config->setId(1);
+ $configs = [$config];
+ $this->provisioningManager->expects($this->once())
+ ->method('getConfigs')
+ ->willReturn($configs);
$this->provisioningManager->expects($this->once())
- ->method('getConfig')
- ->willReturn($config);
- $config->expects($this->once())
- ->method('isActive')
- ->willReturn(true);
+ ->method('provisionSingleUser')
+ ->with($configs, $user);
$credentials = $this->createMock(ICredentials::class);
$this->credentialStore->expects($this->once())
->method('getLoginCredentials')
diff --git a/tests/Unit/Migration/AddSieveToProvisioningConfigTest.php b/tests/Unit/Migration/AddSieveToProvisioningConfigTest.php
deleted file mode 100644
index a8ddcec3c..000000000
--- a/tests/Unit/Migration/AddSieveToProvisioningConfigTest.php
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- *
- * 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\Migration;
-
-use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
-use ChristophWurst\Nextcloud\Testing\TestCase;
-use OCA\Mail\Migration\AddSieveToProvisioningConfig;
-use OCA\Mail\Service\Provisioning\Config;
-use OCP\Migration\IOutput;
-use PHPUnit\Framework\MockObject\MockObject;
-
-class AddSieveToProvisioningConfigTest extends TestCase {
-
- /** @var ServiceMockObject */
- private $mock;
-
- /** @var AddSieveToProvisioningConfig */
- private $repairStep;
-
- protected function setUp(): void {
- parent::setUp();
-
- $this->mock = $this->createServiceMock(AddSieveToProvisioningConfig::class);
- $this->repairStep = $this->mock->getService();
- }
-
-
- public function testRunNoConfigToMigrate() {
- $this->mock->getParameter('config')
- ->expects($this->once())
- ->method('getAppValue')
- ->with('mail', 'installed_version')
- ->willReturn('1.8.0');
-
- /** @var IOutput|MockObject $output */
- $output = $this->createMock(IOutput::class);
- $output->expects($this->never())
- ->method('info');
-
- $this->repairStep->run($output);
- }
-
- public function testRun() {
- $this->mock->getParameter('config')
- ->expects($this->once())
- ->method('getAppValue')
- ->with('mail', 'installed_version')
- ->willReturn('1.8.0');
-
- $this->mock->getParameter('configMapper')
- ->expects($this->once())
- ->method('load')
- ->willReturn(new Config([
- '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',
- ]));
-
- $this->mock->getParameter('configMapper')
- ->expects($this->once())
- ->method('save')
- ->with(new Config([
- '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',
- 'sieveEnabled' => false,
- 'sieveHost' => '',
- 'sievePort' => 4190,
- 'sieveUser' => '',
- 'sieveSslMode' => 'tls',
- ]));
-
- /** @var IOutput|MockObject $output */
- $output = $this->createMock(IOutput::class);
- $output->expects($this->once())
- ->method('info')
- ->with('added sieve defaults to provisioning config');
-
- $this->repairStep->run($output);
- }
-
- public function testGetName() {
- $this->assertEquals(
- 'Add sieve defaults to provisioning config',
- $this->repairStep->getName()
- );
- }
-}
diff --git a/tests/Unit/Migration/MigrateProvisioningConfigTest.php b/tests/Unit/Migration/MigrateProvisioningConfigTest.php
deleted file mode 100644
index 7a0dc7862..000000000
--- a/tests/Unit/Migration/MigrateProvisioningConfigTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?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);
- }
-}
diff --git a/tests/Unit/Service/Provisioning/ConfigMapperTest.php b/tests/Unit/Service/Provisioning/ConfigMapperTest.php
deleted file mode 100644
index c311cb810..000000000
--- a/tests/Unit/Service/Provisioning/ConfigMapperTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?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);
- }
-}
diff --git a/tests/Unit/Service/Provisioning/ConfigTest.php b/tests/Unit/Service/Provisioning/ConfigTest.php
deleted file mode 100644
index 839bfcb76..000000000
--- a/tests/Unit/Service/Provisioning/ConfigTest.php
+++ /dev/null
@@ -1,220 +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\Provisioning;
-
-use ChristophWurst\Nextcloud\Testing\TestCase;
-use OCA\Mail\Service\Provisioning\Config;
-use OCP\IUser;
-
-class ConfigTest extends TestCase {
- public function testBuildEmailWithUserId() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'email' => '%USERID%@domain.se',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('test');
- $user->expects($this->exactly(2))
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('test@domain.se', $config->buildEmail($user));
- }
-
- public function testBuildEmailWithEmailPlaceholder() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'email' => '%EMAIL%',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('user');
- $user->expects($this->any())
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildEmail($user));
- }
-
- public function testBuildImapUserWithUserId() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'imapUser' => '%USERID%@domain.se',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('test');
- $user->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn(null);
-
- $this->assertEquals('test@domain.se', $config->buildImapUser($user));
- }
-
- public function testBuildImapUserWithEmailPlaceholder() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'imapUser' => '%EMAIL%',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('user');
- $user->expects($this->any())
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildImapUser($user));
- }
-
- public function testBuildImapUserFromDefaultEmail() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'email' => '%EMAIL%',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('user');
- $user->expects($this->exactly(2))
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildImapUser($user));
- }
-
- public function testBuildSmtpUserWithUserId() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'smtpUser' => '%USERID%@domain.se',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('test');
- $user->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn(null);
-
- $this->assertEquals('test@domain.se', $config->buildSmtpUser($user));
- }
-
- public function testBuilldSmtpUserWithEmailPlaceholder() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'smtpUser' => '%EMAIL%',
- ]);
- $user->expects($this->any())
- ->method('getUID')
- ->willReturn(null);
- $user->expects($this->any())
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildSmtpUser($user));
- }
-
- public function testBuildSmtpUserFromDefaultEmail() {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'email' => '%EMAIL%',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('user');
- $user->expects($this->exactly(2))
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildImapUser($user));
- }
-
- public function testBuildSieveUserWithUserId(): void {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'sieveUser' => '%USERID%@domain.se',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('test');
- $user->expects($this->once())
- ->method('getEMailAddress')
- ->willReturn(null);
-
- $this->assertEquals('test@domain.se', $config->buildSieveUser($user));
- }
-
- public function testBuilldSieveUserWithEmailPlaceholder(): void {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'sieveUser' => '%EMAIL%',
- ]);
- $user->expects($this->once())
- ->method('getUID')
- ->willReturn(null);
- $user->expects($this->exactly(2))
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildSieveUser($user));
- }
-
- public function testBuildSieveUserFromDefaultEmail(): void {
- $user = $this->createMock(IUser::class);
- $config = new Config([
- 'email' => '%EMAIL%',
- ]);
- $user->expects($this->exactly(2))
- ->method('getUID')
- ->willReturn('user');
- $user->expects($this->exactly(2))
- ->method('getEMailAddress')
- ->willReturn('user@domain.se');
-
- $this->assertEquals('user@domain.se', $config->buildSieveUser($user));
- }
-
- /**
- * @param string $key
- * @param mixed $value
- * @dataProvider providerTestGetter
- */
- public function testGetter(string $key, $value): void {
- $config = new Config([
- $key => $value
- ]);
- $this->assertEquals($value, $config->{'get' . ucfirst($key)}());
- }
-
- public function providerTestGetter(): array {
- return [
- 'smtpHost' => ['smtpHost', 'smtp.domain.com'],
- 'smtpPort' => ['smtpPort', 465],
- 'smtpSslMode' => ['smtpSslMode', 'tls'],
- 'imapHost' => ['imapHost', 'imap.domain.com'],
- 'imapPort' => ['imapPort', 993],
- 'imapSslMode' => ['imapSslMode', 'tls'],
- 'sieveEnabled' => ['sieveEnabled', true],
- 'sieveHost' => ['sieveHost', 'imap.domain.com'],
- 'sievePort' => ['sieveHost', 4190],
- 'sieveSslMode' => ['sieveSslMode', 'tls'],
- ];
- }
-}
diff --git a/tests/Unit/Service/Provisioning/ManagerTest.php b/tests/Unit/Service/Provisioning/ManagerTest.php
index 81b0ede1e..2b2dd9449 100644
--- a/tests/Unit/Service/Provisioning/ManagerTest.php
+++ b/tests/Unit/Service/Provisioning/ManagerTest.php
@@ -25,7 +25,7 @@ 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\Db\Provisioning;
use OCA\Mail\Service\Provisioning\Manager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IUser;
@@ -43,24 +43,30 @@ class ManagerTest extends TestCase {
parent::setUp();
$this->mock = $this->createServiceMock(Manager::class);
+ /** @var MockObject $manager */
$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);
+ $cnt = $this->manager->provision();
$this->assertEquals(0, $cnt);
}
public function testUpdateProvisionSingleUser() {
/** @var IUser|MockObject $user */
- $user = $this->createMock(IUser::class);
- $config = new TestConfig();
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
+ $config = new Provisioning();
+ $config->setId(1);
+ $config->setProvisioningDomain('batman.com');
+ $config->setEmailTemplate('%USER%@batman.com');
+ $configs = [$config];
$account = $this->createMock(MailAccount::class);
$this->mock->getParameter('mailAccountMapper')
->expects($this->once())
@@ -71,13 +77,20 @@ class ManagerTest extends TestCase {
->method('update')
->with($account);
- $this->manager->provisionSingleUser($config, $user);
+ $result = $this->manager->provisionSingleUser($configs, $user);
+ $this->assertTrue($result);
}
public function testProvisionSingleUser() {
/** @var IUser|MockObject $user */
- $user = $this->createMock(IUser::class);
- $config = new TestConfig();
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
+ $config = new Provisioning();
+ $config->setId(1);
+ $config->setProvisioningDomain('batman.com');
+ $config->setEmailTemplate('%USER%@batman.com');
+ $configs = [$config];
$this->mock->getParameter('mailAccountMapper')
->expects($this->once())
->method('findProvisionedAccount')
@@ -86,54 +99,89 @@ class ManagerTest extends TestCase {
->expects($this->once())
->method('insert');
- $this->manager->provisionSingleUser($config, $user);
- }
-
- public function testGetNoConfig() {
- $config = $this->manager->getConfig();
-
- $this->assertNull($config);
+ $result = $this->manager->provisionSingleUser($configs, $user);
+ $this->assertTrue($result);
}
- public function testGetConfig() {
- $config = $this->createMock(Config::class);
- $this->mock->getParameter('configMapper')
+ public function testUpdateProvisionSingleUserWithWildcard() {
+ /** @var IUser|MockObject $user */
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
+ $config = new Provisioning();
+ $config->setId(1);
+ $config->setProvisioningDomain('*');
+ $config->setEmailTemplate('%USER%@batman.com');
+ $configs = [$config];
+ $account = $this->createMock(MailAccount::class);
+ $this->mock->getParameter('mailAccountMapper')
->expects($this->once())
- ->method('load')
- ->willReturn($config);
-
- $cfg = $this->manager->getConfig();
+ ->method('findProvisionedAccount')
+ ->willReturn($account);
+ $this->mock->getParameter('mailAccountMapper')
+ ->expects($this->once())
+ ->method('update')
+ ->with($account);
- $this->assertSame($config, $cfg);
+ $result = $this->manager->provisionSingleUser($configs, $user);
+ $this->assertTrue($result);
}
- public function testDeprovision() {
- $config = new TestConfig();
+ public function testProvisionSingleUserWithWildcard() {
+ /** @var IUser|MockObject $user */
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
+ $config = new Provisioning();
+ $config->setId(1);
+ $config->setProvisioningDomain('*');
+ $config->setEmailTemplate('%USER%@batman.com');
+ $configs = [$config];
$this->mock->getParameter('mailAccountMapper')
->expects($this->once())
- ->method('deleteProvisionedAccounts');
- $this->mock->getParameter('configMapper')
- ->expects($this->once())
- ->method('load')
- ->willReturn($config);
- $this->mock->getParameter('configMapper')
+ ->method('findProvisionedAccount')
+ ->willThrowException($this->createMock(DoesNotExistException::class));
+ $this->mock->getParameter('mailAccountMapper')
->expects($this->once())
- ->method('save')
- ->willReturn($config);
+ ->method('insert');
- $this->manager->deprovision();
+ $result = $this->manager->provisionSingleUser($configs, $user);
+ $this->assertTrue($result);
+ }
- $this->assertEquals(false, $config->jsonSerialize()['active']);
+ public function testProvisionSingleUserNoDomainMatch() {
+ /** @var IUser|MockObject $user */
+ $user = $this->createConfiguredMock(IUser::class, [
+ 'getEmailAddress' => 'bruce.wayne@batman.com'
+ ]);
+ $config = new Provisioning();
+ $config->setId(1);
+ $config->setProvisioningDomain('arkham-asylum.com');
+ $config->setEmailTemplate('%USER%@batman.com');
+ $configs = [$config];
+ $this->mock->getParameter('mailAccountMapper')
+ ->expects($this->never())
+ ->method('findProvisionedAccount');
+ $this->mock->getParameter('mailAccountMapper')
+ ->expects($this->never())
+ ->method('update');
+ $this->mock->getParameter('mailAccountMapper')
+ ->expects($this->never())
+ ->method('insert');
+
+ $result = $this->manager->provisionSingleUser($configs, $user);
+ $this->assertFalse($result);
}
- public function testImportConfig() {
- $this->mock->getParameter('configMapper')
+ public function testDeprovision() {
+ $config = new Provisioning();
+ $config->setProvisioningDomain('*');
+ $config->setId(1);
+ $this->mock->getParameter('mailAccountMapper')
->expects($this->once())
- ->method('save');
+ ->method('deleteProvisionedAccounts');
- $this->manager->importConfig([
- 'email' => '%USERID%@domain.com',
- ]);
+ $this->manager->deprovision($config);
}
public function testUpdatePasswordNotProvisioned() {
@@ -165,25 +213,48 @@ class ManagerTest extends TestCase {
}
public function testNewProvisioning() {
- $this->mock->getParameter('configMapper')
+ $config = new Provisioning([
+ 'active' => true,
+ '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',
+ 'sieveEnabled' => false,
+ 'sieveUser' => '',
+ 'sieveHost' => '',
+ 'sievePort' => 0,
+ 'sieveSslMode' => 'tls'
+ ]);
+ $this->mock->getParameter('provisioningMapper')
->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',
- false,
- '',
- '',
- 0,
- 'tls'
- );
+ ->method('validate')
+ ->willReturn($config);
+
+ $this->mock->getParameter('provisioningMapper')
+ ->expects($this->once())
+ ->method('insert');
+
+ $this->manager->newProvisioning([
+ 'active' => true,
+ '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',
+ 'sieveEnabled' => false,
+ 'sieveUser' => '',
+ 'sieveHost' => '',
+ 'sievePort' => 0,
+ 'sieveSslMode' => 'tls'
+ ]);
}
}