Skip to content

Commit a32f165

Browse files
Merge pull request #5198 from nextcloud/enh/5173/ldap-aliases-provisioning
LDAP alias provisioning
2 parents a59a5fb + 8fb14b5 commit a32f165

File tree

19 files changed

+806
-208
lines changed

19 files changed

+806
-208
lines changed

lib/Controller/AliasesController.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public function show() {
7272
* @NoAdminRequired
7373
* @TrapError
7474
*/
75-
public function update() {
76-
throw new NotImplemented();
75+
public function update(int $id, string $alias, string $aliasName): JSONResponse {
76+
return new JSONResponse($this->aliasService->update($this->currentUserId, $id, $alias, $aliasName));
7777
}
7878

7979
/**
@@ -84,7 +84,7 @@ public function update() {
8484
* @return JSONResponse
8585
*/
8686
public function destroy(int $id): JSONResponse {
87-
return new JSONResponse($this->aliasService->delete($id, $this->currentUserId));
87+
return new JSONResponse($this->aliasService->delete($this->currentUserId, $id));
8888
}
8989

9090
/**
@@ -116,7 +116,6 @@ public function create(int $accountId, string $alias, string $aliasName): JSONRe
116116
* @throws DoesNotExistException
117117
*/
118118
public function updateSignature(int $id, string $signature = null): JSONResponse {
119-
$this->aliasService->updateSignature($this->currentUserId, $id, $signature);
120-
return new JSONResponse();
119+
return new JSONResponse($this->aliasService->updateSignature($this->currentUserId, $id, $signature));
121120
}
122121
}

lib/Controller/SettingsController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,20 @@ public function createProvisioning(array $data): JSONResponse {
6060
$this->provisioningManager->newProvisioning($data);
6161
} catch (ValidationException $e) {
6262
return HttpJsonResponse::fail([$e->getFields()]);
63+
} catch (\Exception $e) {
64+
return HttpJsonResponse::fail([$e->getMessage()]);
6365
}
6466

6567
return new JSONResponse([]);
6668
}
6769

6870
public function updateProvisioning(int $id, array $data): JSONResponse {
6971
try {
70-
$this->provisioningManager->updateProvisioning(array_merge(
71-
$data,
72-
['id' => $id]
73-
));
72+
$this->provisioningManager->updateProvisioning(array_merge($data, ['id' => $id]));
7473
} catch (ValidationException $e) {
7574
return HttpJsonResponse::fail([$e->getFields()]);
75+
} catch (\Exception $e) {
76+
return HttpJsonResponse::fail([$e->getMessage()]);
7677
}
7778

7879
return new JSONResponse([]);

lib/Db/Alias.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
namespace OCA\Mail\Db;
2525

2626
use JsonSerializable;
27-
2827
use OCP\AppFramework\Db\Entity;
2928

3029
/**
@@ -36,6 +35,8 @@
3635
* @method string getAlias()
3736
* @method void setSignature(string|null $signature)
3837
* @method string|null getSignature()
38+
* @method void setProvisioningId(int $provisioningId)
39+
* @method int|null getProvisioningId()
3940
*/
4041
class Alias extends Entity implements JsonSerializable {
4142

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

55+
/** @var int|null */
56+
protected $provisioningId;
57+
5458
public function __construct() {
5559
$this->addType('accountId', 'int');
5660
$this->addType('name', 'string');
5761
$this->addType('alias', 'string');
62+
$this->addType('provisioningId', 'int');
63+
}
64+
65+
public function isProvisioned(): bool {
66+
return $this->getProvisioningId() !== null;
5867
}
5968

6069
public function jsonSerialize(): array {
@@ -63,6 +72,7 @@ public function jsonSerialize(): array {
6372
'name' => $this->getName(),
6473
'alias' => $this->getAlias(),
6574
'signature' => $this->getSignature(),
75+
'provisioned' => $this->isProvisioned(),
6676
];
6777
}
6878
}

lib/Db/AliasMapper.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function __construct(IDBConnection $db) {
4141
*/
4242
public function find(int $aliasId, string $currentUserId): Alias {
4343
$qb = $this->db->getQueryBuilder();
44-
$qb->select('aliases.*')
44+
$qb->select('aliases.*', 'accounts.provisioning_id')
4545
->from($this->getTableName(), 'aliases')
4646
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
4747
->where(
@@ -54,6 +54,24 @@ public function find(int $aliasId, string $currentUserId): Alias {
5454
return $this->findEntity($qb);
5555
}
5656

57+
/**
58+
* @throws DoesNotExistException
59+
*/
60+
public function findByAlias(string $alias, string $currentUserId): Alias {
61+
$qb = $this->db->getQueryBuilder();
62+
$qb->select('aliases.*', 'accounts.provisioning_id')
63+
->from($this->getTableName(), 'aliases')
64+
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
65+
->where(
66+
$qb->expr()->andX(
67+
$qb->expr()->eq('accounts.user_id', $qb->createNamedParameter($currentUserId)),
68+
$qb->expr()->eq('aliases.alias', $qb->createNamedParameter($alias))
69+
)
70+
);
71+
72+
return $this->findEntity($qb);
73+
}
74+
5775
/**
5876
* @param int $accountId
5977
* @param string $currentUserId
@@ -62,7 +80,7 @@ public function find(int $aliasId, string $currentUserId): Alias {
6280
*/
6381
public function findAll(int $accountId, string $currentUserId): array {
6482
$qb = $this->db->getQueryBuilder();
65-
$qb->select('aliases.*')
83+
$qb->select('aliases.*', 'accounts.provisioning_id')
6684
->from($this->getTableName(), 'aliases')
6785
->join('aliases', 'mail_accounts', 'accounts', $qb->expr()->eq('aliases.account_id', 'accounts.id'))
6886
->where(
@@ -89,6 +107,29 @@ public function deleteAll($accountId) {
89107
$query->execute();
90108
}
91109

110+
/**
111+
* Delete all provisioned aliases for the given uid
112+
*
113+
* Exception for Nextcloud 20: \Doctrine\DBAL\DBALException
114+
* Exception for Nextcloud 21 and newer: \OCP\DB\Exception
115+
*
116+
* @TODO: Change throws to \OCP\DB\Exception once Mail does not support Nextcloud 20.
117+
*
118+
* @throws \Exception
119+
*/
120+
public function deleteProvisionedAliasesByUid(string $uid): void {
121+
$qb = $this->db->getQueryBuilder();
122+
123+
$qb->delete($this->getTableName(), 'aliases')
124+
->join('aliases', 'mail_accounts', 'accounts', 'accounts.id = aliases.account_id')
125+
->where(
126+
$qb->expr()->eq('accounts.user_id', $qb->createNamedParameter($uid)),
127+
$qb->expr()->isNotNull('provisioning_id')
128+
);
129+
130+
$qb->execute();
131+
}
132+
92133
public function deleteOrphans(): void {
93134
$qb1 = $this->db->getQueryBuilder();
94135
$idsQuery = $qb1->select('a.id')

lib/Db/Provisioning.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@
6060
* @method void setSieveSslMode(?string $sieveSslMode)
6161
* @method string|null getSieveUser()
6262
* @method void setSieveUser(?string $sieveUser)
63+
* @method array getAliases()
64+
* @method void setAliases(array $aliases)
65+
* @method bool getLdapAliasesProvisioning()
66+
* @method void setLdapAliasesProvisioning(bool $ldapAliasesProvisioning)
67+
* @method string|null getLdapAliasesAttribute()
68+
* @method void setLdapAliasesAttribute(?string $ldapAliasesAttribute)
6369
*/
6470
class Provisioning extends Entity implements JsonSerializable {
6571
public const WILDCARD = '*';
@@ -79,13 +85,18 @@ class Provisioning extends Entity implements JsonSerializable {
7985
protected $sieveHost;
8086
protected $sievePort;
8187
protected $sieveSslMode;
88+
protected $aliases = [];
89+
protected $ldapAliasesProvisioning;
90+
protected $ldapAliasesAttribute;
8291

8392
public function __construct() {
8493
$this->addType('imapPort', 'integer');
8594
$this->addType('smtpPort', 'integer');
8695
$this->addType('sieveEnabled', 'boolean');
8796
$this->addType('sievePort', 'integer');
97+
$this->addType('ldapAliasesProvisioning', 'boolean');
8898
}
99+
89100
/**
90101
* @return array
91102
*/
@@ -107,6 +118,9 @@ public function jsonSerialize() {
107118
'sieveHost' => $this->getSieveHost(),
108119
'sievePort' => $this->getSievePort(),
109120
'sieveSslMode' => $this->getSieveSslMode(),
121+
'aliases' => $this->getAliases(),
122+
'ldapAliasesProvisioning' => $this->getLdapAliasesProvisioning(),
123+
'ldapAliasesAttribute' => $this->getLdapAliasesAttribute(),
110124
];
111125
}
112126

lib/Db/ProvisioningMapper.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ public function __construct(IDBConnection $db, LoggerInterface $logger) {
5151
*
5252
* @return Provisioning[]
5353
*/
54-
public function getAll() : array {
54+
public function getAll(): array {
5555
$qb = $this->db->getQueryBuilder();
5656
$qb = $qb->select('*')
57-
->from($this->getTableName())
58-
->orderBy('provisioning_domain', 'desc');
57+
->from($this->getTableName())
58+
->orderBy('provisioning_domain', 'desc');
5959
try {
6060
return $this->findEntities($qb);
6161
} catch (DoesNotExistException $e) {
@@ -69,7 +69,7 @@ public function getAll() : array {
6969
* @return Provisioning
7070
* @throws ValidationException
7171
*/
72-
public function validate(array $data) : Provisioning {
72+
public function validate(array $data): Provisioning {
7373
$exception = new ValidationException();
7474

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

106+
$ldapAliasesProvisioning = (bool)($data['ldapAliasesProvisioning'] ?? false);
107+
$ldapAliasesAttribute = $data['ldapAliasesAttribute'] ?? '';
108+
109+
if ($ldapAliasesProvisioning && empty($ldapAliasesAttribute)) {
110+
$exception->setField('ldapAliasesAttribute', false);
111+
}
112+
106113
if (!empty($exception->getFields())) {
107114
throw $exception;
108115
}
109116

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

136+
$provisioning->setLdapAliasesProvisioning($ldapAliasesProvisioning);
137+
$provisioning->setLdapAliasesAttribute($ldapAliasesAttribute);
138+
130139
return $provisioning;
131140
}
132141

133142
public function get(int $id): ?Provisioning {
134143
$qb = $this->db->getQueryBuilder();
135144
$qb = $qb->select('*')
136-
->from($this->getTableName())
137-
->where($qb->expr()->eq('id', $qb->createNamedParameter($id), IQueryBuilder::PARAM_INT));
145+
->from($this->getTableName())
146+
->where($qb->expr()->eq('id', $qb->createNamedParameter($id), IQueryBuilder::PARAM_INT));
138147
try {
139148
return $this->findEntity($qb);
140149
} catch (DoesNotExistException $e) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OCA\Mail\Migration;
6+
7+
use Closure;
8+
use Doctrine\DBAL\Schema\SchemaException;
9+
use OCP\DB\ISchemaWrapper;
10+
use OCP\Migration\IOutput;
11+
use OCP\Migration\SimpleMigrationStep;
12+
13+
class Version1101Date20210616141806 extends SimpleMigrationStep {
14+
/**
15+
* @throws SchemaException
16+
*/
17+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
18+
/** @var ISchemaWrapper $schema */
19+
$schema = $schemaClosure();
20+
21+
$provisioningTable = $schema->getTable('mail_provisionings');
22+
$provisioningTable->addColumn('ldap_aliases_provisioning', 'boolean', [
23+
'notnull' => false,
24+
'default' => false
25+
]);
26+
$provisioningTable->addColumn('ldap_aliases_attribute', 'string', [
27+
'notnull' => false,
28+
'length' => 255,
29+
'default' => '',
30+
]);
31+
32+
return $schema;
33+
}
34+
}

lib/Service/AliasesService.php

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use OCA\Mail\Db\Alias;
2727
use OCA\Mail\Db\AliasMapper;
2828
use OCA\Mail\Db\MailAccountMapper;
29+
use OCA\Mail\Exception\ClientException;
2930
use OCP\AppFramework\Db\DoesNotExistException;
3031

3132
class AliasesService {
@@ -81,15 +82,17 @@ public function create(string $userId, int $accountId, string $alias, string $al
8182
}
8283

8384
/**
84-
* @param int $aliasId
85-
* @param String $currentUserId
86-
* @return Alias
85+
* @throws ClientException
8786
* @throws DoesNotExistException
8887
*/
89-
public function delete(int $aliasId, string $currentUserId): Alias {
90-
$alias = $this->aliasMapper->find($aliasId, $currentUserId);
91-
$this->aliasMapper->delete($alias);
92-
return $alias;
88+
public function delete(string $userId, int $aliasId): Alias {
89+
$entity = $this->aliasMapper->find($aliasId, $userId);
90+
91+
if ($entity->isProvisioned()) {
92+
throw new ClientException('Deleting a provisioned alias is not allowed.');
93+
}
94+
95+
return $this->aliasMapper->delete($entity);
9396
}
9497

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

110+
/**
111+
* Update alias and name
112+
*
113+
* @throws DoesNotExistException
114+
*/
115+
public function update(string $userId, int $aliasId, string $alias, string $aliasName): Alias {
116+
$entity = $this->aliasMapper->find($aliasId, $userId);
117+
118+
if (!$entity->isProvisioned()) {
119+
$entity->setAlias($alias);
120+
}
121+
$entity->setName($aliasName);
122+
123+
return $this->aliasMapper->update($entity);
124+
}
125+
107126
/**
108127
* Update signature for alias
109128
*
110-
* @param string $userId
111-
* @param int $aliasId
112-
* @param string|null $signature
113129
* @throws DoesNotExistException
114130
*/
115-
public function updateSignature(string $userId, int $aliasId, string $signature = null): void {
116-
$alias = $this->find($aliasId, $userId);
117-
$alias->setSignature($signature);
118-
$this->aliasMapper->update($alias);
131+
public function updateSignature(string $userId, int $aliasId, string $signature = null): Alias {
132+
$entity = $this->find($aliasId, $userId);
133+
$entity->setSignature($signature);
134+
return $this->aliasMapper->update($entity);
119135
}
120136
}

0 commit comments

Comments
 (0)