Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add internal addresses #9891

Merged
merged 1 commit into from
Aug 13, 2024
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
15 changes: 15 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,21 @@
'url' => '/api/trustedsenders',
'verb' => 'GET'
],
[
'name' => 'internal_address#setAddress',
'url' => '/api/internalAddress/{address}',
'verb' => 'PUT'
],
[
'name' => 'internal_address#removeAddress',
'url' => '/api/internalAddress/{address}',
'verb' => 'DELETE'
],
[
'name' => 'internal_address#list',
'url' => '/api/internalAddress',
'verb' => 'GET'
],
[
'name' => 'sieve#updateAccount',
'url' => '/api/sieve/account/{id}',
Expand Down
24 changes: 24 additions & 0 deletions lib/Contracts/IInternalAddressService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Contracts;

use OCA\Mail\Db\InternalAddress;

interface IInternalAddressService {
public function isInternal(string $uid, string $address): bool;

public function add(string $uid, string $address, string $type, ?bool $trust = true);

/**
* @param string $uid
* @return InternalAddress[]
*/
public function getInternalAddresses(string $uid): array;
}
90 changes: 90 additions & 0 deletions lib/Controller/InternalAddressController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Controller;

use OCA\Mail\AppInfo\Application;
use OCA\Mail\Http\JsonResponse;
use OCA\Mail\Http\TrapError;
use OCA\Mail\Service\InternalAddressService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest;

class InternalAddressController extends Controller {
private ?string $uid;

public function __construct(IRequest $request,
?string $userId,
private InternalAddressService $internalAddressService) {
parent::__construct(Application::APP_ID, $request);

$this->internalAddressService = $internalAddressService;
$this->uid = $userId;
}

/**
* @NoAdminRequired
*
* @param string $address
* @param string $type
* @return JsonResponse
*/
#[TrapError]
public function setAddress(string $address, string $type): JsonResponse {
$address = $this->internalAddressService->add(
$this->uid,
$address,
$type
)->jsonSerialize();

return JsonResponse::success($address, Http::STATUS_CREATED);
}

/**
* @NoAdminRequired
*
* @param string $address
* @param string $type
* @return JsonResponse
*/
#[TrapError]
public function removeAddress(string $address, string $type): JsonResponse {
if($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);
}

$this->internalAddressService->add(
$this->uid,
hamza221 marked this conversation as resolved.
Show resolved Hide resolved
$address,
$type,
false
);

return JsonResponse::success();
}

/**
* @NoAdminRequired
hamza221 marked this conversation as resolved.
Show resolved Hide resolved
*
* @return JsonResponse
*/
#[TrapError]
public function list(): JsonResponse {
if($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);
}
$list = $this->internalAddressService->getInternalAddresses(
$this->uid
hamza221 marked this conversation as resolved.
Show resolved Hide resolved
);

return JsonResponse::success($list);
}
}
16 changes: 15 additions & 1 deletion lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use OCA\Mail\Service\AiIntegrations\AiIntegrationsService;
use OCA\Mail\Service\AliasesService;
use OCA\Mail\Service\Classification\ClassificationSettingsService;
use OCA\Mail\Service\InternalAddressService;
use OCA\Mail\Service\OutboxService;
use OCA\Mail\Service\SmimeService;
use OCA\Viewer\Event\LoadViewer;
Expand Down Expand Up @@ -70,6 +71,7 @@ class PageController extends Controller {
private IUserManager $userManager;
private ?IAvailabilityCoordinator $availabilityCoordinator;
private ClassificationSettingsService $classificationSettingsService;
private InternalAddressService $internalAddressService;

public function __construct(string $appName,
IRequest $request,
Expand All @@ -91,7 +93,8 @@ public function __construct(string $appName,
AiIntegrationsService $aiIntegrationsService,
IUserManager $userManager,
ContainerInterface $container,
ClassificationSettingsService $classificationSettingsService) {
ClassificationSettingsService $classificationSettingsService,
InternalAddressService $internalAddressService, ) {
parent::__construct($appName, $request);

$this->urlGenerator = $urlGenerator;
Expand All @@ -112,6 +115,7 @@ public function __construct(string $appName,
$this->aiIntegrationsService = $aiIntegrationsService;
$this->userManager = $userManager;
$this->classificationSettingsService = $classificationSettingsService;
$this->internalAddressService = $internalAddressService;
hamza221 marked this conversation as resolved.
Show resolved Hide resolved

// TODO: inject directly if support for nextcloud < 28 is dropped
try {
Expand Down Expand Up @@ -173,6 +177,16 @@ public function index(): TemplateResponse {
$this->tagMapper->getAllTagsForUser($this->currentUserId)
);

$this->initialStateService->provideInitialState(
'internal-addresses-list',
$this->internalAddressService->getInternalAddresses($this->currentUserId)
);

$this->initialStateService->provideInitialState(
'internal-addresses',
$this->preferences->getPreference($this->currentUserId, 'internal-addresses', false)
);

$this->initialStateService->provideInitialState(
'sort-order',
$this->preferences->getPreference($this->currentUserId, 'sort-order', 'newest')
Expand Down
39 changes: 39 additions & 0 deletions lib/Db/InternalAddress.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use JsonSerializable;
use OCP\AppFramework\Db\Entity;
use ReturnTypeWillChange;

/**
* @method setAddress(string $address): void
* @method getAddress(): string
* @method setUserId(string $userId): void
* @method getUserId(): string
* @method setType(string $type): void
* @method getType(): string
*/
class InternalAddress extends Entity implements JsonSerializable {

protected $address ;
protected $userId;
protected $type;

#[ReturnTypeWillChange]
public function jsonSerialize() {
return [
'id' => $this->id,
'address' => $this->address,
'uid' => $this->userId,
'type' => $this->type,
];
}
}
103 changes: 103 additions & 0 deletions lib/Db/InternalAddressMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection;

/**
* @template-extends QBMapper<InternalAddress>
*/
class InternalAddressMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'mail_internal_address');
}

public function exists(string $uid, string $address): bool {
hamza221 marked this conversation as resolved.
Show resolved Hide resolved

$emailObject = new \Horde_Mail_Rfc822_Address($address);
$host = $emailObject->host;
$qb = $this->db->getQueryBuilder();

$select = $qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->orX(
$qb->expr()->andX(
$qb->expr()->eq('address', $qb->createNamedParameter($address)),
$qb->expr()->eq('type', $qb->createNamedParameter('individual'))
),
$qb->expr()->andX(
$qb->expr()->eq('address', $qb->createNamedParameter($host)),
$qb->expr()->eq('type', $qb->createNamedParameter('domain'))
)
),
$qb->expr()->eq('user_id', $qb->createNamedParameter($uid))
);

$rows = $this->findEntities($select);

return $rows !== [];
}

public function create(string $uid, string $address, string $type): int {

$address = InternalAddress::fromParams([
'userId' => $uid,
'address' => $address,
'type' => $type,
]);

$result = $this->insert($address);

return $result->getId();
}

public function remove(string $uid, string $address, string $type): void {
$qb = $this->db->getQueryBuilder();

$delete = $qb->delete($this->getTableName())
->where(
$qb->expr()->eq('user_id', $qb->createNamedParameter($uid)),
$qb->expr()->eq('address', $qb->createNamedParameter($address)),
$qb->expr()->eq('type', $qb->createNamedParameter($type))
);

$delete->executeStatement();
}

/**
* @param string $uid
* @return InternalAddress[]
*/
public function findAll(string $uid): array {
$qb = $this->db->getQueryBuilder();
$select = $qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($uid)));
return $this->findEntities($select);
}

public function find(string $uid, string $address): ?InternalAddress {
$qb = $this->db->getQueryBuilder();
$select = $qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->eq('user_id', $qb->createNamedParameter($uid)),
$qb->expr()->eq('address', $qb->createNamedParameter($address))
);
try {
return $this->findEntity($select);
} catch (DoesNotExistException $e) {
return null;
}
}
}
54 changes: 54 additions & 0 deletions lib/Migration/Version4000Date20240716172702.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version4000Date20240716172702 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->createTable('mail_internal_address');

$table->addColumn('id', Types::INTEGER, [
'autoincrement' => true,
'notnull' => true,
'length' => 4,
]);
$table->addColumn('address', Types::STRING, [
'notnull' => true,
'length' => 255,
]);
$table->addColumn('type', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('user_id', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['address', 'user_id'], 'mail_internal_address_uniq');

return $schema;
}


}
Loading
Loading