Skip to content

Commit

Permalink
Make it possible to mark messages important
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
  • Loading branch information
ChristophWurst committed Apr 23, 2020
1 parent 2bf7d91 commit e8772da
Show file tree
Hide file tree
Showing 13 changed files with 651 additions and 2 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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)!
]]></description>
<version>1.3.3</version>
<version>1.4.0</version>
<licence>agpl</licence>
<author>Christoph Wurst</author>
<author>Roeland Jago Douma</author>
Expand Down
3 changes: 3 additions & 0 deletions css/mail.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions img/important.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions lib/Db/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -76,6 +78,7 @@ class Message extends Entity implements JsonSerializable {
'forwarded',
'junk',
'notjunk',
'important',
];

protected $uid;
Expand All @@ -94,6 +97,7 @@ class Message extends Entity implements JsonSerializable {
protected $updatedAt;
protected $structureAnalyzed;
protected $flagAttachments;
protected $flagImportant;
protected $previewText;

/** @var AddressList */
Expand Down Expand Up @@ -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');
}

Expand Down Expand Up @@ -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(),
Expand Down
56 changes: 56 additions & 0 deletions lib/Migration/Version1040Date20200422130220.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace OCA\Mail\Migration;

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

class Version1040Date20200422130220 extends SimpleMigrationStep {

/** @var IDBConnection */
protected $connection;

public function __construct(IDBConnection $connection) {
$this->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();
}

}
117 changes: 117 additions & 0 deletions lib/Migration/Version1040Date20200422142920.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);

namespace OCA\Mail\Migration;

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

class Version1040Date20200422142920 extends SimpleMigrationStep {

/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
*
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$messagesTable = $schema->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;
}

}
1 change: 1 addition & 0 deletions lib/Model/IMAPMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
102 changes: 102 additions & 0 deletions lib/Service/Classification/OftenContactedSenderClassifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

declare(strict_types=1);

/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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 <http://www.gnu.org/licenses/>.
*/

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;
}
}
Loading

0 comments on commit e8772da

Please sign in to comment.