Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions lib/Controller/AliasesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public function show() {
* @NoAdminRequired
* @TrapError
*/
public function update() {
throw new NotImplemented();
public function update(int $id, string $alias, string $aliasName): JSONResponse {
return new JSONResponse($this->aliasService->update($this->currentUserId, $id, $alias, $aliasName));
}

/**
Expand All @@ -84,7 +84,7 @@ public function update() {
* @return JSONResponse
*/
public function destroy(int $id): JSONResponse {
return new JSONResponse($this->aliasService->delete($id, $this->currentUserId));
return new JSONResponse($this->aliasService->delete($this->currentUserId, $id));
}

/**
Expand Down Expand Up @@ -116,7 +116,6 @@ public function create(int $accountId, string $alias, string $aliasName): JSONRe
* @throws DoesNotExistException
*/
public function updateSignature(int $id, string $signature = null): JSONResponse {
$this->aliasService->updateSignature($this->currentUserId, $id, $signature);
return new JSONResponse();
return new JSONResponse($this->aliasService->updateSignature($this->currentUserId, $id, $signature));
}
}
9 changes: 5 additions & 4 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,20 @@ public function createProvisioning(array $data): JSONResponse {
$this->provisioningManager->newProvisioning($data);
} catch (ValidationException $e) {
return HttpJsonResponse::fail([$e->getFields()]);
} catch (\Exception $e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you elaborate why this was widened?

return HttpJsonResponse::fail([$e->getMessage()]);
}

return new JSONResponse([]);
}

public function updateProvisioning(int $id, array $data): JSONResponse {
try {
$this->provisioningManager->updateProvisioning(array_merge(
$data,
['id' => $id]
));
$this->provisioningManager->updateProvisioning(array_merge($data, ['id' => $id]));
} catch (ValidationException $e) {
return HttpJsonResponse::fail([$e->getFields()]);
} catch (\Exception $e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same. Could this possibly be a ClientException? \Error will throw almost anything. That anything could also be from unexpected service errors, then the HTTP4xx isn't appropriate IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$this->provisioningManager->newProvisioning($data); throws a validation exception if input data is invalid or a exception related to the database. I guess we can migrate this to Throwable and HttpJsonResponse.errorFromThrowable.

return HttpJsonResponse::fail([$e->getMessage()]);
}

return new JSONResponse([]);
Expand Down
12 changes: 11 additions & 1 deletion lib/Db/Alias.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
namespace OCA\Mail\Db;

use JsonSerializable;

use OCP\AppFramework\Db\Entity;

/**
Expand All @@ -36,6 +35,8 @@
* @method string getAlias()
* @method void setSignature(string|null $signature)
* @method string|null getSignature()
* @method void setProvisioningId(int $provisioningId)
* @method int|null getProvisioningId()
*/
class Alias extends Entity implements JsonSerializable {

Expand All @@ -51,10 +52,18 @@ class Alias extends Entity implements JsonSerializable {
/** @var string|null */
protected $signature;

/** @var int|null */
protected $provisioningId;

public function __construct() {
$this->addType('accountId', 'int');
$this->addType('name', 'string');
$this->addType('alias', 'string');
$this->addType('provisioningId', 'int');
}

public function isProvisioned(): bool {
return $this->getProvisioningId() !== null;
}

public function jsonSerialize(): array {
Expand All @@ -63,6 +72,7 @@ public function jsonSerialize(): array {
'name' => $this->getName(),
'alias' => $this->getAlias(),
'signature' => $this->getSignature(),
'provisioned' => $this->isProvisioned(),
];
}
}
45 changes: 43 additions & 2 deletions lib/Db/AliasMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct(IDBConnection $db) {
*/
public function find(int $aliasId, string $currentUserId): Alias {
$qb = $this->db->getQueryBuilder();
$qb->select('aliases.*')
$qb->select('aliases.*', 'accounts.provisioning_id')
->from($this->getTableName(), 'aliases')
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
->where(
Expand All @@ -54,6 +54,24 @@ public function find(int $aliasId, string $currentUserId): Alias {
return $this->findEntity($qb);
}

/**
* @throws DoesNotExistException
*/
public function findByAlias(string $alias, string $currentUserId): Alias {
$qb = $this->db->getQueryBuilder();
$qb->select('aliases.*', 'accounts.provisioning_id')
->from($this->getTableName(), 'aliases')
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
->where(
$qb->expr()->andX(
$qb->expr()->eq('accounts.user_id', $qb->createNamedParameter($currentUserId)),
$qb->expr()->eq('aliases.alias', $qb->createNamedParameter($alias))
)
);

return $this->findEntity($qb);
}

/**
* @param int $accountId
* @param string $currentUserId
Expand All @@ -62,7 +80,7 @@ public function find(int $aliasId, string $currentUserId): Alias {
*/
public function findAll(int $accountId, string $currentUserId): array {
$qb = $this->db->getQueryBuilder();
$qb->select('aliases.*')
$qb->select('aliases.*', 'accounts.provisioning_id')
->from($this->getTableName(), 'aliases')
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
->where(
Expand All @@ -89,6 +107,29 @@ public function deleteAll($accountId) {
$query->execute();
}

/**
* Delete all provisioned aliases for the given uid
*
* Exception for Nextcloud 20: \Doctrine\DBAL\DBALException
* Exception for Nextcloud 21 and newer: \OCP\DB\Exception
*
* @TODO: Change throws to \OCP\DB\Exception once Mail does not support Nextcloud 20.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I think we do this soon-ish so we only have to support two major versions

*
* @throws \Exception
*/
public function deleteProvisionedAliasesByUid(string $uid): void {
$qb = $this->db->getQueryBuilder();

$qb->delete($this->getTableName(), 'aliases')
->join('aliases', 'mail_accounts', 'accounts', 'accounts.id = aliases.account_id')
->where(
$qb->expr()->eq('accounts.user_id', $qb->createNamedParameter($uid)),
$qb->expr()->isNotNull('provisioning_id')
);

$qb->execute();
}

public function deleteOrphans(): void {
$qb1 = $this->db->getQueryBuilder();
$idsQuery = $qb1->select('a.id')
Expand Down
14 changes: 14 additions & 0 deletions lib/Db/Provisioning.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
* @method void setSieveSslMode(?string $sieveSslMode)
* @method string|null getSieveUser()
* @method void setSieveUser(?string $sieveUser)
* @method array getAliases()
* @method void setAliases(array $aliases)
* @method bool getLdapAliasesProvisioning()
* @method void setLdapAliasesProvisioning(bool $ldapAliasesProvisioning)
* @method string|null getLdapAliasesAttribute()
* @method void setLdapAliasesAttribute(?string $ldapAliasesAttribute)
*/
class Provisioning extends Entity implements JsonSerializable {
public const WILDCARD = '*';
Expand All @@ -79,13 +85,18 @@ class Provisioning extends Entity implements JsonSerializable {
protected $sieveHost;
protected $sievePort;
protected $sieveSslMode;
protected $aliases = [];
protected $ldapAliasesProvisioning;
protected $ldapAliasesAttribute;

public function __construct() {
$this->addType('imapPort', 'integer');
$this->addType('smtpPort', 'integer');
$this->addType('sieveEnabled', 'boolean');
$this->addType('sievePort', 'integer');
$this->addType('ldapAliasesProvisioning', 'boolean');
}

/**
* @return array
*/
Expand All @@ -107,6 +118,9 @@ public function jsonSerialize() {
'sieveHost' => $this->getSieveHost(),
'sievePort' => $this->getSievePort(),
'sieveSslMode' => $this->getSieveSslMode(),
'aliases' => $this->getAliases(),
'ldapAliasesProvisioning' => $this->getLdapAliasesProvisioning(),
'ldapAliasesAttribute' => $this->getLdapAliasesAttribute(),
];
}

Expand Down
23 changes: 16 additions & 7 deletions lib/Db/ProvisioningMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ public function __construct(IDBConnection $db, LoggerInterface $logger) {
*
* @return Provisioning[]
*/
public function getAll() : array {
public function getAll(): array {
$qb = $this->db->getQueryBuilder();
$qb = $qb->select('*')
->from($this->getTableName())
->orderBy('provisioning_domain', 'desc');
->from($this->getTableName())
->orderBy('provisioning_domain', 'desc');
try {
return $this->findEntities($qb);
} catch (DoesNotExistException $e) {
Expand All @@ -69,7 +69,7 @@ public function getAll() : array {
* @return Provisioning
* @throws ValidationException
*/
public function validate(array $data) : Provisioning {
public function validate(array $data): Provisioning {
$exception = new ValidationException();

if (!isset($data['provisioningDomain']) || $data['provisioningDomain'] === '') {
Expand Down Expand Up @@ -103,11 +103,17 @@ public function validate(array $data) : Provisioning {
$exception->setField('smtpSslMode', false);
}

$ldapAliasesProvisioning = (bool)($data['ldapAliasesProvisioning'] ?? false);
$ldapAliasesAttribute = $data['ldapAliasesAttribute'] ?? '';

if ($ldapAliasesProvisioning && empty($ldapAliasesAttribute)) {
$exception->setField('ldapAliasesAttribute', false);
}

if (!empty($exception->getFields())) {
throw $exception;
}


$provisioning = new Provisioning();
$provisioning->setId($data['id'] ?? null);
$provisioning->setProvisioningDomain($data['provisioningDomain']);
Expand All @@ -127,14 +133,17 @@ public function validate(array $data) : Provisioning {
$provisioning->setSievePort($data['sievePort'] ?? null);
$provisioning->setSieveSslMode($data['sieveSslMode'] ?? '');

$provisioning->setLdapAliasesProvisioning($ldapAliasesProvisioning);
$provisioning->setLdapAliasesAttribute($ldapAliasesAttribute);

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));
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id), IQueryBuilder::PARAM_INT));
try {
return $this->findEntity($qb);
} catch (DoesNotExistException $e) {
Expand Down
34 changes: 34 additions & 0 deletions lib/Migration/Version1101Date20210616141806.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace OCA\Mail\Migration;

use Closure;
use Doctrine\DBAL\Schema\SchemaException;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version1101Date20210616141806 extends SimpleMigrationStep {
/**
* @throws SchemaException
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$provisioningTable = $schema->getTable('mail_provisionings');
$provisioningTable->addColumn('ldap_aliases_provisioning', 'boolean', [
'notnull' => false,
'default' => false
]);
$provisioningTable->addColumn('ldap_aliases_attribute', 'string', [
'notnull' => false,
'length' => 255,
'default' => '',
]);

return $schema;
}
}
44 changes: 30 additions & 14 deletions lib/Service/AliasesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use OCA\Mail\Db\Alias;
use OCA\Mail\Db\AliasMapper;
use OCA\Mail\Db\MailAccountMapper;
use OCA\Mail\Exception\ClientException;
use OCP\AppFramework\Db\DoesNotExistException;

class AliasesService {
Expand Down Expand Up @@ -81,15 +82,17 @@ public function create(string $userId, int $accountId, string $alias, string $al
}

/**
* @param int $aliasId
* @param String $currentUserId
* @return Alias
* @throws ClientException
* @throws DoesNotExistException
*/
public function delete(int $aliasId, string $currentUserId): Alias {
$alias = $this->aliasMapper->find($aliasId, $currentUserId);
$this->aliasMapper->delete($alias);
return $alias;
public function delete(string $userId, int $aliasId): Alias {
$entity = $this->aliasMapper->find($aliasId, $userId);

if ($entity->isProvisioned()) {
throw new ClientException('Deleting a provisioned alias is not allowed.');
}

return $this->aliasMapper->delete($entity);
}

/**
Expand All @@ -104,17 +107,30 @@ public function deleteAll($accountId): void {
$this->aliasMapper->deleteAll($accountId);
}

/**
* Update alias and name
*
* @throws DoesNotExistException
*/
public function update(string $userId, int $aliasId, string $alias, string $aliasName): Alias {
$entity = $this->aliasMapper->find($aliasId, $userId);

if (!$entity->isProvisioned()) {
$entity->setAlias($alias);
}
$entity->setName($aliasName);

return $this->aliasMapper->update($entity);
}

/**
* Update signature for alias
*
* @param string $userId
* @param int $aliasId
* @param string|null $signature
* @throws DoesNotExistException
*/
public function updateSignature(string $userId, int $aliasId, string $signature = null): void {
$alias = $this->find($aliasId, $userId);
$alias->setSignature($signature);
$this->aliasMapper->update($alias);
public function updateSignature(string $userId, int $aliasId, string $signature = null): Alias {
$entity = $this->find($aliasId, $userId);
$entity->setSignature($signature);
return $this->aliasMapper->update($entity);
}
}
Loading