diff --git a/appinfo/info.xml b/appinfo/info.xml index d964279f3d..c7037f13f4 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -12,7 +12,7 @@ - **🙈 We’re not reinventing the wheel!** Based on the great [Horde](http://horde.org) libraries. - **📬 Want to host your own mail server?** We don’t have to reimplement this as you could set up [Mail-in-a-Box](https://mailinabox.email)! ]]> - 1.3.3 + 1.4.0 agpl Christoph Wurst Roeland Jago Douma diff --git a/css/mail.scss b/css/mail.scss index e66fac7b5a..bdd23ac5ca 100755 --- a/css/mail.scss +++ b/css/mail.scss @@ -331,6 +331,9 @@ .icon-drafts { @include icon-color('drafts', 'mail', $color-black); } +.icon-important { + @include icon-color('important', 'mail', $color-black); +} .icon-sent { @include icon-color('sent', 'mail', $color-black); } diff --git a/img/important.svg b/img/important.svg new file mode 100644 index 0000000000..710dfffbd5 --- /dev/null +++ b/img/important.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/Db/Message.php b/lib/Db/Message.php index e2c0bbb4bb..c909b73480 100644 --- a/lib/Db/Message.php +++ b/lib/Db/Message.php @@ -61,6 +61,8 @@ * @method bool getStructureAnalyzed() * @method void setFlagAttachments(?bool $hasAttachments) * @method null|bool getFlagAttachments() + * @method void setFlagImportant(bool $important) + * @method bool getFlagImportant() * @method void setPreviewText(?string $subject) * @method null|string getPreviewText() * @method void setUpdatedAt(int $time) @@ -76,6 +78,7 @@ class Message extends Entity implements JsonSerializable { 'forwarded', 'junk', 'notjunk', + 'important', ]; protected $uid; @@ -94,6 +97,7 @@ class Message extends Entity implements JsonSerializable { protected $updatedAt; protected $structureAnalyzed; protected $flagAttachments; + protected $flagImportant; protected $previewText; /** @var AddressList */ @@ -126,6 +130,7 @@ public function __construct() { $this->addType('flagNotjunk', 'bool'); $this->addType('structureAnalyzed', 'bool'); $this->addType('flagAttachments', 'bool'); + $this->addType('flagImportant', 'bool'); $this->addType('updatedAt', 'integer'); } @@ -210,6 +215,7 @@ public function jsonSerialize() { 'draft' => $this->getFlagDraft(), 'forwarded' => $this->getFlagForwarded(), 'hasAttachments' => $this->getFlagAttachments() ?? false, + 'important' => $this->getFlagImportant(), ], 'from' => $this->getFrom()->jsonSerialize(), 'to' => $this->getTo()->jsonSerialize(), diff --git a/lib/Migration/Version1040Date20200422130220.php b/lib/Migration/Version1040Date20200422130220.php new file mode 100644 index 0000000000..d830cc4ce7 --- /dev/null +++ b/lib/Migration/Version1040Date20200422130220.php @@ -0,0 +1,56 @@ +connection = $connection; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * + * @return ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $schema->dropTable('mail_messages'); + + return $schema; + } + + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + // Reset locks and sync tokens + $qb1 = $this->connection->getQueryBuilder(); + $updateMailboxes = $qb1->update('mail_mailboxes') + ->set('sync_new_lock', $qb1->createNamedParameter(null)) + ->set('sync_new_token', $qb1->createNamedParameter(null)) + ->set('sync_changed_lock', $qb1->createNamedParameter(null)) + ->set('sync_changed_token', $qb1->createNamedParameter(null)) + ->set('sync_vanished_lock', $qb1->createNamedParameter(null)) + ->set('sync_vanished_token', $qb1->createNamedParameter(null)); + $updateMailboxes->execute(); + + // Clean up some orphaned data + $qb2 = $this->connection->getQueryBuilder(); + $deleteRecipients = $qb2->delete('mail_recipients'); + $deleteRecipients->execute(); + } + +} diff --git a/lib/Migration/Version1040Date20200422142920.php b/lib/Migration/Version1040Date20200422142920.php new file mode 100644 index 0000000000..666a1b92c3 --- /dev/null +++ b/lib/Migration/Version1040Date20200422142920.php @@ -0,0 +1,117 @@ +createTable('mail_messages'); + $messagesTable->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 20, + ]); + $messagesTable->addColumn('uid', 'integer', [ + 'notnull' => true, + 'length' => 4, + ]); + $messagesTable->addColumn('message_id', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $messagesTable->addColumn('mailbox_id', 'integer', [ + 'notnull' => true, + 'length' => 20, + ]); + $messagesTable->addColumn('subject', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $messagesTable->addColumn('sent_at', 'integer', [ + 'notnull' => true, + 'length' => 4, + ]); + $messagesTable->addColumn('flag_answered', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_deleted', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_draft', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_flagged', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_seen', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_forwarded', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_junk', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_notjunk', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('flag_attachments', 'boolean', [ + 'notnull' => false, + ]); + $messagesTable->addColumn('flag_important', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('structure_analyzed', 'boolean', [ + 'notnull' => true, + 'default' => false, + ]); + $messagesTable->addColumn('preview_text', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $messagesTable->addColumn('updated_at', 'integer', [ + 'notnull' => false, + 'length' => 4, + ]); + $messagesTable->setPrimaryKey(['id']); + // We allow each UID just once + $messagesTable->addUniqueIndex( + [ + 'uid', + 'mailbox_id', + ], + 'mail_msg_mb_uid_idx' + ); + $messagesTable->addIndex(['sent_at'], 'mail_msg_sent_idx'); + + return $schema; + } + +} diff --git a/lib/Model/IMAPMessage.php b/lib/Model/IMAPMessage.php index 3b7be10606..3e055f2ccc 100644 --- a/lib/Model/IMAPMessage.php +++ b/lib/Model/IMAPMessage.php @@ -646,6 +646,7 @@ public function toDbMessage(int $mailboxId): \OCA\Mail\Db\Message { $msg->setFlagForwarded(in_array(Horde_Imap_Client::FLAG_FORWARDED, $flags, true)); $msg->setFlagJunk(in_array(Horde_Imap_Client::FLAG_JUNK, $flags, true)); $msg->setFlagNotjunk(in_array(Horde_Imap_Client::FLAG_NOTJUNK, $flags, true)); + $msg->setFlagImportant(false); $msg->setFlagAttachments(false); return $msg; diff --git a/lib/Service/Classification/OftenContactedSenderClassifier.php b/lib/Service/Classification/OftenContactedSenderClassifier.php new file mode 100644 index 0000000000..4fe95ff0ef --- /dev/null +++ b/lib/Service/Classification/OftenContactedSenderClassifier.php @@ -0,0 +1,102 @@ + + * + * @author 2020 Christoph Wurst + * + * @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\Service\Classification; + +use OCA\Mail\Account; +use OCA\Mail\Address; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Db\Message; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class OftenContactedSenderClassifier extends AClassifier { + use SafeRatio; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IDBConnection */ + private $db; + + public function __construct(MailboxMapper $mailboxMapper, + IDBConnection $db) { + $this->mailboxMapper = $mailboxMapper; + $this->db = $db; + } + + public function isImportant(Account $account, Mailbox $mailbox, Message $message): bool { + $sender = $message->getTo()->first(); + if ($sender === null) { + return false; + } + + try { + $mb = $this->mailboxMapper->findSpecial($account, 'sent'); + } catch (DoesNotExistException $e) { + return false; + } + + return $this->greater( + $this->getMessagesSentTo($mb, $sender->getEmail()), + $this->getMessagesSentTotal($mb), + 0.1, + true // The very first message is important + ); + } + + private function getMessagesSentTotal(Mailbox $mb): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.id', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } + + private function getMessagesSentTo(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.id', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } +} diff --git a/lib/Service/Classification/OftenImportantSenderClassifier.php b/lib/Service/Classification/OftenImportantSenderClassifier.php new file mode 100644 index 0000000000..fb95cda04b --- /dev/null +++ b/lib/Service/Classification/OftenImportantSenderClassifier.php @@ -0,0 +1,103 @@ + + * + * @author 2020 Christoph Wurst + * + * @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\Service\Classification; + +use OCA\Mail\Account; +use OCA\Mail\Address; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Db\Message; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class OftenImportantSenderClassifier extends AClassifier { + use SafeRatio; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IDBConnection */ + private $db; + + public function __construct(MailboxMapper $mailboxMapper, + IDBConnection $db) { + $this->mailboxMapper = $mailboxMapper; + $this->db = $db; + } + + public function isImportant(Account $account, Mailbox $mailbox, Message $message): bool { + $sender = $message->getTo()->first(); + if ($sender === null) { + return false; + } + + try { + $mb = $this->mailboxMapper->findSpecial($account, 'inbox'); + } catch (DoesNotExistException $e) { + return false; + } + + return $this->greater( + $this->getNrOfImportantMessages($mb, $sender->getEmail()), + $this->getNumberOfMessages($mb, $sender->getEmail()), + 0.3 + ); + } + + private function getNrOfImportantMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('m.flag_important', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } + + private function getNumberOfMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } +} diff --git a/lib/Service/Classification/OftenReadSenderClassifier.php b/lib/Service/Classification/OftenReadSenderClassifier.php new file mode 100644 index 0000000000..7eaf86e576 --- /dev/null +++ b/lib/Service/Classification/OftenReadSenderClassifier.php @@ -0,0 +1,103 @@ + + * + * @author 2020 Christoph Wurst + * + * @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\Service\Classification; + +use OCA\Mail\Account; +use OCA\Mail\Address; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Db\Message; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class OftenReadSenderClassifier extends AClassifier { + use SafeRatio; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IDBConnection */ + private $db; + + public function __construct(MailboxMapper $mailboxMapper, + IDBConnection $db) { + $this->mailboxMapper = $mailboxMapper; + $this->db = $db; + } + + public function isImportant(Account $account, Mailbox $mailbox, Message $message): bool { + $sender = $message->getTo()->first(); + if ($sender === null) { + return false; + } + + try { + $mb = $this->mailboxMapper->findSpecial($account, 'inbox'); + } catch (DoesNotExistException $e) { + return false; + } + + return $this->greater( + $this->getNrOfReadMessages($mb, $sender->getEmail()), + $this->getNumberOfMessages($mb, $sender->getEmail()), + 0.9 + ); + } + + private function getNrOfReadMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('m.flag_seen', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } + + private function getNumberOfMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } +} diff --git a/lib/Service/Classification/OftenRepliedSenderClassifier.php b/lib/Service/Classification/OftenRepliedSenderClassifier.php new file mode 100644 index 0000000000..2f3f869270 --- /dev/null +++ b/lib/Service/Classification/OftenRepliedSenderClassifier.php @@ -0,0 +1,103 @@ + + * + * @author 2020 Christoph Wurst + * + * @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\Service\Classification; + +use OCA\Mail\Account; +use OCA\Mail\Address; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Db\Message; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class OftenRepliedSenderClassifier extends AClassifier { + use SafeRatio; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var IDBConnection */ + private $db; + + public function __construct(MailboxMapper $mailboxMapper, + IDBConnection $db) { + $this->mailboxMapper = $mailboxMapper; + $this->db = $db; + } + + public function isImportant(Account $account, Mailbox $mailbox, Message $message): bool { + $sender = $message->getTo()->first(); + if ($sender === null) { + return false; + } + + try { + $mb = $this->mailboxMapper->findSpecial($account, 'inbox'); + } catch (DoesNotExistException $e) { + return false; + } + + return $this->greater( + $this->getNrOfRepliedMessages($mb, $sender->getEmail()), + $this->getNumberOfMessages($mb, $sender->getEmail()), + 0.1 + ); + } + + private function getNrOfRepliedMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('m.flag_answered', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } + + private function getNumberOfMessages(Mailbox $mb, string $email): int { + $qb = $this->db->getQueryBuilder(); + + $select = $qb->select($qb->func()->count('*')) + ->from('mail_recipients', 'r') + ->join('r', 'mail_messages', 'm', $qb->expr()->eq('m.id', 'r.message_id', IQueryBuilder::PARAM_INT)) + ->join('r', 'mail_mailboxes', 'mb', $qb->expr()->eq('mb.id', $qb->expr()->castColumn('m.mailbox_id', IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('r.type', $qb->createNamedParameter(Address::TYPE_FROM), IQueryBuilder::PARAM_INT)) + ->andWhere($qb->expr()->eq('mb.id', $qb->createNamedParameter($mb->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('r.email', $qb->createNamedParameter($email))); + $result = $select->execute(); + $cnt = $result->fetchColumn(); + $result->closeCursor(); + return (int)$cnt; + } +} diff --git a/src/components/Envelope.vue b/src/components/Envelope.vue index 5b76fa32a7..89e465349d 100644 --- a/src/components/Envelope.vue +++ b/src/components/Envelope.vue @@ -1,5 +1,9 @@