Skip to content

Commit

Permalink
feat: mail snippets
Browse files Browse the repository at this point in the history
Signed-off-by: Hamza Mahjoubi <[email protected]>
  • Loading branch information
hamza221 committed Jan 9, 2025
1 parent 6711d8e commit 5400b1a
Show file tree
Hide file tree
Showing 25 changed files with 1,992 additions and 7 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The rating depends on the installed text processing backend. See [the rating ove
Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud.com/blog/nextcloud-ethical-ai-rating/).
]]></description>
<version>4.2.0-alpha.2</version>
<version>4.2.0-alpha.3</version>
<licence>agpl</licence>
<author homepage="https://github.com/ChristophWurst">Christoph Wurst</author>
<author homepage="https://github.com/GretaD">GretaD</author>
Expand Down
40 changes: 40 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,46 @@
'url' => '/api/follow-up/check-message-ids',
'verb' => 'POST',
],
[
'name' => 'snippet#getOwnSnippets',
'url' => '/api/snippets',
'verb' => 'GET',
],
[
'name' => 'snippet#getSharedSnippets',
'url' => '/api/snippets/share',
'verb' => 'GET',
],
[
'name' => 'snippet#getShares',
'url' => '/api/snippets/share/shares/{id}',
'verb' => 'GET',
],
[
'name' => 'snippet#create',
'url' => '/api/snippets',
'verb' => 'POST',
],
[
'name' => 'snippet#update',
'url' => '/api/snippets',
'verb' => 'PUT',
],
[
'name' => 'snippet#delete',
'url' => '/api/snippets/{id}',
'verb' => 'DELETE',
],
[
'name' => 'snippet#share',
'url' => '/api/snippets/share',
'verb' => 'POST',
],
[
'name' => 'snippet#deleteShare',
'url' => '/api/snippets/share/{snippetId}/{shareWith}',
'verb' => 'DELETE',
],
],
'resources' => [
'accounts' => ['url' => '/api/accounts'],
Expand Down
197 changes: 197 additions & 0 deletions lib/Controller/SnippetController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<?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\Db\SnippetShare;
use OCA\Mail\Http\JsonResponse;
use OCA\Mail\Http\TrapError;
use OCA\Mail\Service\SnippetService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest;

class SnippetController extends Controller {
private ?string $uid;

public function __construct(

Check warning on line 26 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L26

Added line #L26 was not covered by tests
IRequest $request,
?string $userId,
private SnippetService $snippetService,
) {
parent::__construct(Application::APP_ID, $request);
$this->uid = $userId;

Check warning on line 32 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L31-L32

Added lines #L31 - L32 were not covered by tests
}

/**
* @NoAdminRequired
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 40 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L40

Added line #L40 was not covered by tests
public function getOwnSnippets(): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 43 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L42-L43

Added lines #L42 - L43 were not covered by tests
}
$snippets = $this->snippetService->findAll($this->uid);

Check warning on line 45 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L45

Added line #L45 was not covered by tests

return JsonResponse::success($snippets);

Check warning on line 47 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L47

Added line #L47 was not covered by tests
}

/**
* @NoAdminRequired
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 55 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L55

Added line #L55 was not covered by tests
public function getSharedSnippets(): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 58 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L57-L58

Added lines #L57 - L58 were not covered by tests
}
try {
$snippets = $this->snippetService->findAllSharedWithMe($this->uid);
} catch (DoesNotExistException $e) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 63 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L61-L63

Added lines #L61 - L63 were not covered by tests
}

return JsonResponse::success($snippets);

Check warning on line 66 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L66

Added line #L66 was not covered by tests
}

/**
* @NoAdminRequired
* @param string $title
* @param string $content
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 76 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L76

Added line #L76 was not covered by tests
public function create(string $title, string $content): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 79 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L78-L79

Added lines #L78 - L79 were not covered by tests
}
$snippet = $this->snippetService->create($this->uid, $title, $content);

Check warning on line 81 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L81

Added line #L81 was not covered by tests

return JsonResponse::success($snippet, Http::STATUS_CREATED);

Check warning on line 83 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L83

Added line #L83 was not covered by tests
}

/**
* @NoAdminRequired
* @param int $id
* @param string $title
* @param string $content
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 94 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L94

Added line #L94 was not covered by tests
public function update(int $id, string $title, string $content): JsonResponse {

if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 98 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L97-L98

Added lines #L97 - L98 were not covered by tests
}

$snippet = $this->snippetService->find($id, $this->uid);

Check warning on line 101 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L101

Added line #L101 was not covered by tests

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 104 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L103-L104

Added lines #L103 - L104 were not covered by tests
}

$this->snippetService->update($id, $this->uid, $title, $content);

Check warning on line 107 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L107

Added line #L107 was not covered by tests

return JsonResponse::success($snippet, Http::STATUS_OK);

Check warning on line 109 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L109

Added line #L109 was not covered by tests
}

public function delete(int $id): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 114 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L112-L114

Added lines #L112 - L114 were not covered by tests
}
try {
$this->snippetService->delete($id, $this->uid);
return JsonResponse::success();
} catch (DoesNotExistException $e) {
return JsonResponse::fail('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 120 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L117-L120

Added lines #L117 - L120 were not covered by tests
}
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
* @param string $type
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 132 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L132

Added line #L132 was not covered by tests
public function share(int $snippetId, string $shareWith, string $type): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 135 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L134-L135

Added lines #L134 - L135 were not covered by tests
}

$snippet = $this->snippetService->find($snippetId, $this->uid);

Check warning on line 138 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L138

Added line #L138 was not covered by tests

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 141 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L140-L141

Added lines #L140 - L141 were not covered by tests
}

switch ($type) {
case SnippetShare::TYPE_USER:
$this->snippetService->share($snippetId, $shareWith);
return JsonResponse::success();
case SnippetShare::TYPE_GROUP:
$this->snippetService->shareWithGroup($snippetId, $shareWith);
return JsonResponse::success();

Check warning on line 150 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L145-L150

Added lines #L145 - L150 were not covered by tests
default:
return JsonResponse::fail('Invalid share type', Http::STATUS_BAD_REQUEST);

Check warning on line 152 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L152

Added line #L152 was not covered by tests
}

}

public function getShares(int $id): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 159 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L157-L159

Added lines #L157 - L159 were not covered by tests
}

$snippet = $this->snippetService->find($id, $this->uid);

Check warning on line 162 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L162

Added line #L162 was not covered by tests

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 165 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L164-L165

Added lines #L164 - L165 were not covered by tests
}

$shares = $this->snippetService->getShares($id);

Check warning on line 168 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L168

Added line #L168 was not covered by tests

return JsonResponse::success($shares);

Check warning on line 170 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L170

Added line #L170 was not covered by tests
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 180 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L180

Added line #L180 was not covered by tests
public function deleteShare(int $snippetId, string $shareWith): JsonResponse {
if ($this->uid === null) {
return JsonResponse::error('User not found', Http::STATUS_UNAUTHORIZED);

Check warning on line 183 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L182-L183

Added lines #L182 - L183 were not covered by tests
}

$snippet = $this->snippetService->find($snippetId, $this->uid);

Check warning on line 186 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L186

Added line #L186 was not covered by tests

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 189 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L188-L189

Added lines #L188 - L189 were not covered by tests
}

$this->snippetService->unshare($snippetId, $shareWith);

Check warning on line 192 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L192

Added line #L192 was not covered by tests

return JsonResponse::success();

Check warning on line 194 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L194

Added line #L194 was not covered by tests
}

}
49 changes: 49 additions & 0 deletions lib/Db/Snippet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?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 string getOwner()
* @method void setOwner(string $owner)
* @method string getTitle()
* @method void setTitle(string $title)
* @method string getContent()
* @method void setContent(string $content)
* @method string getPreview()
* @method void setPreview(string $preview)
*/
class Snippet extends Entity implements JsonSerializable {
protected $owner;
protected $title;
protected $content;
protected $preview;

public function __construct() {
$this->addType('owner', 'string');
$this->addType('title', 'string');
$this->addType('content', 'string');
$this->addType('preview', 'string');
}

#[ReturnTypeWillChange]

Check warning on line 39 in lib/Db/Snippet.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/Snippet.php#L39

Added line #L39 was not covered by tests
public function jsonSerialize() {
return [
'id' => $this->getId(),
'owner' => $this->getOwner(),
'title' => $this->getTitle(),
'content' => $this->getContent(),
'preview' => $this->getPreview(),
];

Check warning on line 47 in lib/Db/Snippet.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/Snippet.php#L41-L47

Added lines #L41 - L47 were not covered by tests
}
}
84 changes: 84 additions & 0 deletions lib/Db/SnippetMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?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 OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
* @template-extends QBMapper<Snippet>
*/
class SnippetMapper extends QBMapper {
/**
* @param IDBConnection $db
*/
public function __construct(IDBConnection $db) {
parent::__construct($db, 'mail_snippets');

Check warning on line 25 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L24-L25

Added lines #L24 - L25 were not covered by tests
}

/**
* @param int $id
* @param string $owner
* @return Snippet|null
*/
public function find(int $id, string $owner): ?Snippet {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('owner', $qb->createNamedParameter($owner)));

Check warning on line 38 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L33-L38

Added lines #L33 - L38 were not covered by tests
try {
return $this->findEntity($qb);
} catch (DoesNotExistException $e) {
return null;

Check warning on line 42 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L40-L42

Added lines #L40 - L42 were not covered by tests
}
}

/**
* @param string $owner
* @return Snippet[]
*/
public function findAll(string $owner): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->eq('owner', $qb->createNamedParameter($owner, IQueryBuilder::PARAM_STR))
);

Check warning on line 56 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L50-L56

Added lines #L50 - L56 were not covered by tests

return $this->findEntities($qb);

Check warning on line 58 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L58

Added line #L58 was not covered by tests
}

/**
* @param string $userId
* @param array $groups
* @return Snippet[]
*/
public function findSharedWithMe(string $userId, array $groups): array {
$qb = $this->db->getQueryBuilder();
$qb->select('s.*')
->from($this->getTableName(), 's')
->join('s', 'mail_snippets_shares', 'share', $qb->expr()->eq('s.id', 'share.snippet_id'))
->where($qb->expr()->andX(
$qb->expr()->eq('share.share_with', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
$qb->expr()->eq('share.type', $qb->createNamedParameter('user', IQueryBuilder::PARAM_STR))
))
->orWhere(
$qb->expr()->andX(
$qb->expr()->in('share.share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->eq('share.type', $qb->createNamedParameter('group', IQueryBuilder::PARAM_STR))
)
);
return $this->findEntities($qb);

Check warning on line 81 in lib/Db/SnippetMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetMapper.php#L66-L81

Added lines #L66 - L81 were not covered by tests
}

}
Loading

0 comments on commit 5400b1a

Please sign in to comment.