From 5381d7db62b9739243c9cfe1d94faf6f3e369605 Mon Sep 17 00:00:00 2001 From: hamza221 Date: Mon, 18 Sep 2023 19:09:24 +0200 Subject: [PATCH] fixup! feat: delete tags Signed-off-by: hamza221 --- appinfo/routes.php | 2 +- lib/Contracts/IMailManager.php | 2 +- lib/Controller/TagsController.php | 20 ++++++++--- lib/Db/MessageTags.php | 51 +++++++++++++++++++++++++++ lib/Db/MessageTagsMapper.php | 57 +++++++++++++++++++++++++++++++ lib/Service/MailManager.php | 25 ++++++++++++-- src/components/DeleteTagModal.vue | 5 +++ src/components/TagModal.vue | 5 ++- src/service/MessageService.js | 6 ++-- src/store/actions.js | 4 +-- 10 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 lib/Db/MessageTags.php create mode 100644 lib/Db/MessageTagsMapper.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 78e1220f8e..42705a6202 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -132,7 +132,7 @@ ], [ 'name' => 'tags#delete', - 'url' => '/api/tags/{id}', + 'url' => '/api/tags/{id}/tags/{accountId}', 'verb' => 'DELETE' ], [ diff --git a/lib/Contracts/IMailManager.php b/lib/Contracts/IMailManager.php index 8900c0226f..59534b65f5 100644 --- a/lib/Contracts/IMailManager.php +++ b/lib/Contracts/IMailManager.php @@ -326,7 +326,7 @@ public function updateTag(int $id, string $displayName, string $color, string $u * @return int * @throws ClientException if the given tag does not exist */ - public function deleteTag(int $id, string $userId): Tag; + public function deleteTag(int $id, string $userId, array $messages, Account $account): Tag; /** * @param Account $srcAccount diff --git a/lib/Controller/TagsController.php b/lib/Controller/TagsController.php index 3f719b5f18..42bfc68324 100644 --- a/lib/Controller/TagsController.php +++ b/lib/Controller/TagsController.php @@ -27,7 +27,10 @@ use OCA\Mail\Contracts\IMailManager; use OCA\Mail\Exception\ClientException; use OCA\Mail\Http\TrapError; +use OCA\Mail\Service\AccountService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; @@ -35,13 +38,17 @@ class TagsController extends Controller { private string $currentUserId; private IMailManager $mailManager; + private AccountService $accountService; + + public function __construct(IRequest $request, string $UserId, - IMailManager $mailManager + IMailManager $mailManager, AccountService $accountService, ) { parent::__construct(Application::APP_ID, $request); $this->currentUserId = $UserId; $this->mailManager = $mailManager; + $this->accountService = $accountService; } /** @@ -89,9 +96,14 @@ public function update(int $id, string $displayName, string $color): JSONRespons * @throws ClientException */ #[TrapError] - public function delete(int $id): JSONResponse { - - $this->mailManager->deleteTag($id, $this->currentUserId); + public function delete(int $id, int $accountId): JSONResponse { + try { + $account = $this->accountService->find($this->currentUserId, $accountId); + $messages = $this->mailManager->getMessagesByTag($this->currentUserId, $id, $account); + } catch (DoesNotExistException $e) { + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + $this->mailManager->deleteTag($id, $this->currentUserId, $messages, $account); return new JSONResponse($id); } diff --git a/lib/Db/MessageTags.php b/lib/Db/MessageTags.php new file mode 100644 index 0000000000..87a426a9dc --- /dev/null +++ b/lib/Db/MessageTags.php @@ -0,0 +1,51 @@ + + * + * @author 2023 Hamza Mahjoubi + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Mail\Db; + +use JsonSerializable; +use OCP\AppFramework\Db\Entity; +use ReturnTypeWillChange; + +/** + * @method string getImapMessageId() + * @method void setImapMessageId(string $imapMessageId) + * @method int getTagId() + * @method void setTagId(int $tagId) + */ +class MessageTags extends Entity implements JsonSerializable { + protected $imapMessageId; + protected $tagId; + + + #[ReturnTypeWillChange] + public function jsonSerialize() { + return [ + 'id' => $this->getId(), + 'imapMessageId' => $this->getImapMessageId(), + 'tagId' => $this->getTagId(), + ]; + } +} diff --git a/lib/Db/MessageTagsMapper.php b/lib/Db/MessageTagsMapper.php new file mode 100644 index 0000000000..d533fd41a9 --- /dev/null +++ b/lib/Db/MessageTagsMapper.php @@ -0,0 +1,57 @@ + + * + * @author 2021 Anna Larch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace OCA\Mail\Db; + +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\IL10N; + +/** + * @template-extends QBMapper + */ +class MessageTagsMapper extends QBMapper { + /** @var IL10N */ + private $l10n; + + public function __construct(IDBConnection $db, + IL10N $l10n) { + parent::__construct($db, 'mail_message_tags'); + $this->l10n = $l10n; + } + + public function getMessagesByTag(int $id): array { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('tag_id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)), + + ); + return $this->findEntities($qb); + } + +} diff --git a/lib/Service/MailManager.php b/lib/Service/MailManager.php index 21b335e177..05c9450516 100644 --- a/lib/Service/MailManager.php +++ b/lib/Service/MailManager.php @@ -36,6 +36,7 @@ use OCA\Mail\Db\MailboxMapper; use OCA\Mail\Db\Message; use OCA\Mail\Db\MessageMapper as DbMessageMapper; +use OCA\Mail\Db\MessageTagsMapper; use OCA\Mail\Db\Tag; use OCA\Mail\Db\TagMapper; use OCA\Mail\Db\ThreadMapper; @@ -99,6 +100,9 @@ class MailManager implements IMailManager { /** @var TagMapper */ private $tagMapper; + /** @var MessageTagsMapper */ + private $messageTagsMapper; + /** @var ThreadMapper */ private $threadMapper; @@ -111,6 +115,7 @@ public function __construct(IMAPClientFactory $imapClientFactory, IEventDispatcher $eventDispatcher, LoggerInterface $logger, TagMapper $tagMapper, + MessageTagsMapper $messageTagsMapper, ThreadMapper $threadMapper) { $this->imapClientFactory = $imapClientFactory; $this->mailboxMapper = $mailboxMapper; @@ -121,6 +126,7 @@ public function __construct(IMAPClientFactory $imapClientFactory, $this->eventDispatcher = $eventDispatcher; $this->logger = $logger; $this->tagMapper = $tagMapper; + $this->messageTagsMapper = $messageTagsMapper; $this->threadMapper = $threadMapper; } @@ -247,6 +253,18 @@ public function getMessage(string $uid, int $id): Message { return $this->dbMessageMapper->findByUserId($uid, $id); } + public function getMessagesByTag(string $uid, int $tagId, Account $account): array { + try { + $messageTags = $this->messageTagsMapper->getMessagesByTag($tagId); + $messages = array_map(function ($messageTag) use ($uid, $account) { + return $this->getByMessageId($account, $messageTag->getImapMessageId()); + }, $messageTags); + } catch (DoesNotExistException $e) { + throw new ClientException('Messages not found', 0, $e); + } + return array_merge(...$messages); + } + /** * @param Horde_Imap_Client_Socket $client * @param Account $account @@ -818,13 +836,16 @@ public function updateTag(int $id, string $displayName, string $color, string $u return $this->tagMapper->update($tag); } - public function deleteTag(int $id, string $userId): Tag { + public function deleteTag(int $id, string $userId, array $messages, Account $account): Tag { try { $tag = $this->tagMapper->getTagForUser($id, $userId); } catch (DoesNotExistException $e) { throw new ClientException('Tag not found', 0, $e); } - + foreach ($messages as $message) { + $mailbox = $this->getMailbox($userId, $message->getMailboxId()); + $this->tagMessage($account, $mailbox->getName(), $message, $tag, false); + } return $this->tagMapper->delete($tag); } diff --git a/src/components/DeleteTagModal.vue b/src/components/DeleteTagModal.vue index d17369a45b..8589d9b187 100644 --- a/src/components/DeleteTagModal.vue +++ b/src/components/DeleteTagModal.vue @@ -47,6 +47,10 @@ export default { type: Object, required: true, }, + accountId: { + type: Number, + required: true, + }, }, data() { return { @@ -62,6 +66,7 @@ export default { try { await this.$store.dispatch('deleteTag', { tag: this.tag, + accountId: this.accountId, }) showSuccess(t('mail', 'Tag: {name} deleted', { name: this.tag.displayName })) this.$emit('close') diff --git a/src/components/TagModal.vue b/src/components/TagModal.vue index c908407cb8..f11c256080 100644 --- a/src/components/TagModal.vue +++ b/src/components/TagModal.vue @@ -97,7 +97,10 @@ - + diff --git a/src/service/MessageService.js b/src/service/MessageService.js index 523d896098..3c776e5d2f 100644 --- a/src/service/MessageService.js +++ b/src/service/MessageService.js @@ -145,9 +145,9 @@ export async function updateEnvelopeTag(id, displayName, color) { await axios.put(url, { displayName, color }) } -export async function deleteTag(id) { - const url = generateUrl('/apps/mail/api/tags/{id}', { - id, +export async function deleteTag(id, accountId) { + const url = generateUrl('/apps/mail/api/tags/{id}/tags/{accountId}', { + id, accountId, }) await axios.delete(url) diff --git a/src/store/actions.js b/src/store/actions.js index 352e7e2da7..9fb5a4c291 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -1270,9 +1270,9 @@ export default { logger.debug('tag updated', { tag, displayName, color }) }) }, - async deleteTag({ commit }, { tag }) { + async deleteTag({ commit }, { tag, accountId }) { return handleHttpAuthErrors(commit, async () => { - await deleteTag(tag.id) + await deleteTag(tag.id, accountId) commit('deleteTag', { id: tag.id }) logger.debug('tag updated', { tag }) })