Skip to content

Commit 70aa887

Browse files
committed
fixup! feat: add delegation backend
Signed-off-by: Hamza <hamzamahjoubi221@gmail.com>
1 parent 88c13a5 commit 70aa887

7 files changed

Lines changed: 199 additions & 15 deletions

File tree

appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ The rating depends on the installed text processing backend. See [the rating ove
3434
3535
Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud.com/blog/nextcloud-ethical-ai-rating/).
3636
]]></description>
37-
<version>5.7.0-rc.1</version>
37+
<version>5.7.0-rc.3</version>
3838
<licence>agpl</licence>
3939
<author homepage="https://github.com/ChristophWurst">Christoph Wurst</author>
4040
<author homepage="https://github.com/GretaD">GretaD</author>

appinfo/routes.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,26 @@
505505
'url' => '/api/follow-up/check-message-ids',
506506
'verb' => 'POST',
507507
],
508+
[
509+
'name' => 'delegation#getDelegatedAccounts',
510+
'url' => '/api/delegations',
511+
'verb' => 'GET',
512+
],
513+
[
514+
'name' => 'delegation#getDelegatedUsers',
515+
'url' => '/api/delegations/{accountId}',
516+
'verb' => 'GET',
517+
],
518+
[
519+
'name' => 'delegation#delegate',
520+
'url' => '/api/delegations/{accountId}',
521+
'verb' => 'POST',
522+
],
523+
[
524+
'name' => 'delegation#unDelegate',
525+
'url' => '/api/delegations/{accountId}/{userId}',
526+
'verb' => 'DELETE',
527+
],
508528
[
509529
'name' => 'textBlockShares#getTextBlockShares',
510530
'url' => '/api/textBlocks/{id}/shares',
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\Controller;
11+
12+
use OCA\Mail\Exception\DelegationExistsException;
13+
use OCA\Mail\Http\TrapError;
14+
use OCA\Mail\Service\AccountService;
15+
use OCA\Mail\Service\DelegationService;
16+
use OCP\AppFramework\Controller;
17+
use OCP\AppFramework\Http;
18+
use OCP\AppFramework\Http\Attribute\OpenAPI;
19+
use OCP\AppFramework\Http\JSONResponse;
20+
use OCP\IRequest;
21+
use OCP\IUserManager;
22+
23+
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
24+
class DelegationController extends Controller {
25+
private ?string $currentUserId;
26+
27+
public function __construct(
28+
string $appName,
29+
IRequest $request,
30+
private DelegationService $delegationService,
31+
private AccountService $accountService,
32+
private IUserManager $userManager,
33+
?string $UserId
34+
) {
35+
parent::__construct($appName, $request);
36+
$this->currentUserId = $UserId;
37+
}
38+
39+
/**
40+
* Get all accounts delegated to the current user
41+
*
42+
* @NoAdminRequired
43+
*
44+
* @return JSONResponse
45+
*/
46+
#[TrapError]
47+
public function getDelegatedAccounts(): JSONResponse {
48+
if ($this->currentUserId === null) {
49+
return new JSONResponse([], Http::STATUS_UNAUTHORIZED);
50+
}
51+
52+
return new JSONResponse(
53+
$this->delegationService->findDelegatedAccountForUser($this->currentUserId)
54+
);
55+
}
56+
57+
/**
58+
* Get all users that have delegation for a given account
59+
*
60+
* @NoAdminRequired
61+
*
62+
* @param int $accountId
63+
* @return JSONResponse
64+
*/
65+
#[TrapError]
66+
public function getDelegatedUsers(int $accountId): JSONResponse {
67+
if ($this->currentUserId === null) {
68+
return new JSONResponse([], Http::STATUS_UNAUTHORIZED);
69+
}
70+
71+
$account = $this->accountService->findById($accountId);
72+
if ($account->getUserId() !== $this->currentUserId) {
73+
return new JSONResponse([], Http::STATUS_NOT_FOUND);
74+
}
75+
76+
return new JSONResponse(
77+
$this->delegationService->findDelegatedToUsersForAccount($accountId)
78+
);
79+
}
80+
81+
/**
82+
* Delegate an account to a user
83+
*
84+
* @NoAdminRequired
85+
*
86+
* @param int $accountId
87+
* @param string $userId
88+
* @return JSONResponse
89+
*/
90+
#[TrapError]
91+
public function delegate(int $accountId, string $userId): JSONResponse {
92+
if ($this->currentUserId === null) {
93+
return new JSONResponse([], Http::STATUS_UNAUTHORIZED);
94+
}
95+
96+
$account = $this->accountService->findById($accountId);
97+
if ($account->getUserId() !== $this->currentUserId) {
98+
return new JSONResponse([], Http::STATUS_NOT_FOUND);
99+
}
100+
101+
if ($userId === $this->currentUserId) {
102+
return new JSONResponse(['message' => 'Cannot delegate to yourself'], Http::STATUS_BAD_REQUEST);
103+
}
104+
105+
if (!$this->userManager->userExists($userId)) {
106+
return new JSONResponse([], Http::STATUS_NOT_FOUND);
107+
}
108+
109+
try {
110+
$delegation = $this->delegationService->delegate($accountId, $userId);
111+
} catch (DelegationExistsException) {
112+
return new JSONResponse(['message' => 'Delegation already exists'], Http::STATUS_CONFLICT);
113+
}
114+
115+
return new JSONResponse($delegation, Http::STATUS_CREATED);
116+
}
117+
118+
/**
119+
* Revoke delegation of an account for a user
120+
*
121+
* @NoAdminRequired
122+
*
123+
* @param int $accountId
124+
* @param string $userId
125+
* @return JSONResponse
126+
*/
127+
#[TrapError]
128+
public function unDelegate(int $accountId, string $userId): JSONResponse {
129+
if ($this->currentUserId === null) {
130+
return new JSONResponse([], Http::STATUS_UNAUTHORIZED);
131+
}
132+
133+
$account = $this->accountService->findById($accountId);
134+
if ($account->getUserId() !== $this->currentUserId) {
135+
return new JSONResponse([], Http::STATUS_NOT_FOUND);
136+
}
137+
138+
$this->delegationService->unDelegate($accountId, $userId);
139+
return new JSONResponse([], Http::STATUS_OK);
140+
}
141+
}

lib/Db/DelegationMapper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function __construct(IDBConnection $db) {
2424
public function findDelegatedAccountsForUser(string $uid): array {
2525
$qb = $this->db->getQueryBuilder();
2626

27-
$select = $qb->select('account_id')
27+
$select = $qb->select('*')
2828
->from($this->getTableName())
2929
->where(
3030
$qb->expr()->eq('user_id', $qb->createNamedParameter($uid))
@@ -33,10 +33,10 @@ public function findDelegatedAccountsForUser(string $uid): array {
3333
return $this->findEntities($select);
3434
}
3535

36-
public function findDelegatedToUsers(string $accountId): array {
36+
public function findDelegatedToUsers(int $accountId): array {
3737
$qb = $this->db->getQueryBuilder();
3838

39-
$select = $qb->select('user_id')
39+
$select = $qb->select('*')
4040
->from($this->getTableName())
4141
->where(
4242
$qb->expr()->eq('account_id', $qb->createNamedParameter($accountId))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\Exception;
11+
12+
use Exception;
13+
14+
class DelegationExistsException extends Exception {
15+
public function __construct(string $message = 'Delegation already exists') {
16+
parent::__construct($message);
17+
}
18+
}

lib/Migration/Version5007Date20260312152753.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
4343
'length' => 64,
4444
]);
4545
$table->setPrimaryKey(['id']);
46+
$table->addUniqueIndex(['account_id', 'user_id'], 'mail_deleg_acc_user_uniq');
4647
if ($schema->hasTable('mail_accounts')) {
4748
$table->addForeignKeyConstraint(
4849
$schema->getTable('mail_accounts'),

lib/Service/DelegationService.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,43 @@
1111

1212
use OCA\Mail\Db\Delegation;
1313
use OCA\Mail\Db\DelegationMapper;
14+
use OCA\Mail\Exception\DelegationExistsException;
1415
use OCP\AppFramework\Db\DoesNotExistException;
15-
use Psr\Log\LoggerInterface;
1616

1717
class DelegationService {
1818

1919
public function __construct(
2020
private DelegationMapper $delegationMapper,
21-
private LoggerInterface $logger,
2221
) {
2322
}
2423

25-
public function delegate(int $accountId, string $userId): void {
24+
public function delegate(int $accountId, string $userId): Delegation {
25+
try {
26+
$this->delegationMapper->find($accountId, $userId);
27+
throw new DelegationExistsException("Delegation already exists for account $accountId and user $userId");
28+
} catch (DoesNotExistException) {
29+
// continue
30+
}
31+
2632
$delegation = new Delegation();
2733
$delegation->setAccountId($accountId);
2834
$delegation->setUserId($userId);
29-
$this->delegationMapper->insert($delegation);
35+
return $this->delegationMapper->insert($delegation);
3036
}
3137

3238
public function findDelegatedAccountForUser(string $userId): array {
3339
return $this->delegationMapper->findDelegatedAccountsForUser($userId);
3440
}
3541

36-
public function findDelegatedToUsersForAccount(string $accountId): array {
42+
public function findDelegatedToUsersForAccount(int $accountId): array {
3743
return $this->delegationMapper->findDelegatedToUsers($accountId);
3844
}
3945

46+
/**
47+
* @throws DoesNotExistException
48+
*/
4049
public function unDelegate(int $accountId, string $userId): void {
41-
try {
42-
$delegation = $this->delegationMapper->find($accountId, $userId);
43-
} catch (DoesNotExistException $e) {
44-
$this->logger->warning("Delegation of account:$accountId not found for user: $userId", ['exception' => $e]);
45-
return;
46-
}
50+
$delegation = $this->delegationMapper->find($accountId, $userId);
4751
$this->delegationMapper->delete($delegation);
4852
}
4953
}

0 commit comments

Comments
 (0)