Skip to content

Commit

Permalink
fixup! Add tagging to messages
Browse files Browse the repository at this point in the history
  • Loading branch information
miaulalala committed Mar 9, 2021
1 parent 9b38a13 commit 38fed03
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 64 deletions.
12 changes: 12 additions & 0 deletions lib/Contracts/IMailManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,18 @@ public function markFolderAsRead(Account $account, Mailbox $mailbox): void;
*/
public function flagMessage(Account $account, string $mailbox, int $uid, string $flag, bool $value): void;

/**
* @param Account $account
* @param string $mailbox
* @param int $uid
* @param string $flag
* @param bool $value
*
* @throws ClientException
* @throws ServiceException
*/
public function tagMessage(Account $account, string $mailbox, int $uid, array $flag, bool $value): void;

/**
* @param Account $account
*
Expand Down
20 changes: 14 additions & 6 deletions lib/Controller/MessagesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Http\AttachmentDownloadResponse;
use OCA\Mail\Http\HtmlResponse;
use OCA\Mail\Model\IMAPMessage;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\ItineraryService;
use OCP\AppFramework\Controller;
Expand Down Expand Up @@ -676,15 +675,15 @@ public function setTag(int $id, int $tagId): JSONResponse {
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($this->currentUserId)));
$qb->execute();
// fetch the label entry
// fetch the first label entry
$column = $qb->fetch(PDO::FETCH_ASSOC);
$qb->closeCursor();

if( $column === false ) {
throw new DoesNotExistException( 'Tag does not exist' );
if ($column === false) {
throw new DoesNotExistException('Tag does not exist');
}

$this->mailManager->tagMessage($account, $mailbox->getName(), $message->getUid(), $tag, 'true');
$this->mailManager->tagMessage($account, $mailbox->getName(), $message->getUid(), $column, true);
// add tagging logic here
return new JSONResponse();
}
Expand All @@ -709,7 +708,16 @@ public function removeTag(int $id, int $tagId): JSONResponse {
} catch (DoesNotExistException $e) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}
// add tagging logic here
$qb = $this->db->getQueryBuilder();
$qb->select()
->from('mail_tags')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($this->currentUserId)));
$qb->execute();
// fetch the first label entry
$column = $qb->fetch(PDO::FETCH_ASSOC);
$qb->closeCursor();
$this->mailManager->tagMessage($account, $mailbox->getName(), $message->getUid(), $column, false);
return new JSONResponse();
}

Expand Down
18 changes: 18 additions & 0 deletions lib/Db/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ class Message extends Entity implements JsonSerializable {
/** @var AddressList */
private $bcc;

/** @var Tag[] */
private $tags = [];

public function __construct() {
$this->from = new AddressList([]);
$this->to = new AddressList([]);
Expand Down Expand Up @@ -199,6 +202,20 @@ public function setTo(AddressList $to): void {
$this->to = $to;
}

/**
* @return array
*/
public function getTags(): array {
return $this->tags;
}

/**
* @param array $tags
*/
public function setTags(array $tags): void {
$this->tags = $tags;
}

/**
* @return AddressList
*/
Expand Down Expand Up @@ -257,6 +274,7 @@ public function jsonSerialize() {
'junk' => $this->getFlagJunk(),
'mdnsent' => $this->getFlagMdnsent(),
],
'tags' => $this->getTags(),
'from' => $this->getFrom()->jsonSerialize(),
'to' => $this->getTo()->jsonSerialize(),
'cc' => $this->getCc()->jsonSerialize(),
Expand Down
68 changes: 53 additions & 15 deletions lib/Db/MessageMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,27 @@

namespace OCA\Mail\Db;

use OCP\IUser;
use function ltrim;
use OCA\Mail\Account;
use OCA\Mail\Address;
use OCA\Mail\AddressList;
use OCA\Mail\IMAP\Threading\DatabaseMessage;
use OCA\Mail\Service\Search\Flag;
use OCA\Mail\Service\Search\FlagExpression;
use OCA\Mail\Service\Search\SearchQuery;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
use RuntimeException;
use function array_combine;
use function array_keys;
use OCP\IDBConnection;
use function array_map;
use function get_class;
use function ltrim;
use function mb_substr;
use function array_keys;
use OCA\Mail\AddressList;
use function array_combine;
use OCA\Mail\Service\Search\Flag;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCA\Mail\Service\Search\SearchQuery;
use OCP\AppFramework\Utility\ITimeFactory;
use OCA\Mail\Service\Search\FlagExpression;
use OCA\Mail\IMAP\Threading\DatabaseMessage;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;

/**
* @template-extends QBMapper<Message>
Expand All @@ -54,10 +55,16 @@ class MessageMapper extends QBMapper {
/** @var ITimeFactory */
private $timeFactory;

/** @var TagMapper */
private $tagMapper;

public function __construct(IDBConnection $db,
ITimeFactory $timeFactory) {
ITimeFactory $timeFactory,
TagMapper $tagMapper
) {
parent::__construct($db, 'mail_messages');
$this->timeFactory = $timeFactory;
$this->tagMapper = $tagMapper;
}

/**
Expand Down Expand Up @@ -309,6 +316,9 @@ public function insertBulk(Message ...$messages): void {
$qb2->execute();
}
}
foreach ($message->getTags() as $tag) {
$this->tagMapper->tagMessage($tag, $message->getMessageId());
}
}

$this->db->commit();
Expand Down Expand Up @@ -360,6 +370,34 @@ public function updateBulk(Message ...$messages): array {
$query->setParameter('flag_important', $message->getFlagImportant(), IQueryBuilder::PARAM_BOOL);

$query->execute();


$mqb = $this->db->getQueryBuilder();
$mqb->select('*')
->from($this->getTableName())
->where($mqb->expr()->eq('message_id', $mqb->createNamedParameter($message->getMessageId())))
->where($mqb->expr()->eq('mailbox_id', $mqb->createNamedParameter($message->getMailboxId())));

try {
$dbMessage = $this->findEntity($mqb);
} catch (MultipleObjectsReturnedException $e) {
continue;
}

$dbTags = $dbMessage->getTags();
$imapTags = $message->getTags();

if (empty($imapTags) && empty($dbTags)) {
continue;
}
$toRemove = array_diff($imapTags, $dbTags);
$toAdd = array_diff($dbTags, $imapTags);
foreach ($toAdd as $tag) {
$this->tagMapper->tagMessage($tag, $message->getMessageId());
}
foreach ($toRemove as $tag) {
$this->tagMapper->untagMessage($tag,$message->getMessageId());
}
}

$this->db->commit();
Expand Down
4 changes: 2 additions & 2 deletions lib/Db/Tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
class Tag extends Entity implements JsonSerializable {
protected $userId;
protected $displayName;
protected $imapKeyword;
protected $imapLabel;
protected $color;

public function __construct() {
Expand All @@ -52,7 +52,7 @@ public function jsonSerialize() {
'databaseId' => $this->getId(),
'userId' => $this->getUserId(),
'displayName' => $this->getDisplayName(),
'imapKeyword' => $this->getImapKeyword(),
'imapLabel' => $this->getImapKeyword(),
'color' => $this->getColor(),
];
}
Expand Down
50 changes: 17 additions & 33 deletions lib/Db/TagMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\AppFramework\Db\DoesNotExistException;

/**
* @template-extends QBMapper<Message>
Expand All @@ -45,53 +46,36 @@ public function __construct(IDBConnection $db,
$this->timeFactory = $timeFactory;
}

// public function getTagsForMessage(Message $message): array {
// $qb1 = $this->db->getQueryBuilder();
// $qb2 = $this->db->getQueryBuilder();
// $qb2->select('id')
// ->from('mail_message_tags')
// ->where('imap_message_id', $qb1->createNamedParameter($message->getMessageId()));

// $qb1->select('*')
// ->from($this->getTableName())
// ->where(
// $qb1->expr()->in('id', $qb1->createFunction($qb2->getSQL()), IQueryBuilder::PARAM_INT_ARRAY)
// );

// return $this->findEntities($qb1);
// }

// public function getTagsForUser(string $userId) {
// $qb = $this->db->getQueryBuilder();
// $qb->select()
// ->from('mail_tags')
// ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
// $qb->execute();

// return $this->findEntities($qb);
// }

public function getTagByImapLabel(string $imapLabel): Entity {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from('mail_tags')
->where($qb->expr()->eq('imap_keyword', $qb->createNamedParameter($imapLabel)));
->where($qb->expr()->eq('imap_label', $qb->createNamedParameter($imapLabel)));
$result = $this->findEntity($qb);
return $result;
}

public function tagMessage(Tag $tag, string $messageId) {
/** @var Tag $exists */
$exists = $this->getTagByImapLabel($tag->getImapKeyword());
if ($exists === false) {
$tag = $this->insert($tag);
} else {
try {
$exists = $this->getTagByImapLabel($tag->getImapLabel());
$tag->setId($exists->getId());
} catch (DoesNotExistException $e) {
$tag = $this->insert($tag);
}

$qb = $this->db->getQueryBuilder();
$qb->insert('mail_message_tags');
$qb->setValue('message_id', $messageId);
$qb->setValue('tag_id', $tag->getId());
$qb->setValue('imap_message_id', $qb->createNamedParameter($messageId));
$qb->setValue('tag_id', $qb->createNamedParameter($tag->getId(), IQueryBuilder::PARAM_INT));
$qb->execute();
}

public function untagMessage(Tag $tag, string $messageId) {
$qb = $this->db->getQueryBuilder();
$qb->delete('mail_message_tags')
->where($qb->expr()->eq('imap_message_id', $qb->createNamedParameter($messageId)))
->where($qb->expr()->eq('tag_id', $qb->createNamedParameter($tag->getId())));
$qb->execute();
}
}
49 changes: 47 additions & 2 deletions lib/Migration/Version1100Date20210304143008.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace OCA\Mail\Migration;

use Closure;
use OCA\Mail\Db\TagMapper;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
Expand All @@ -14,6 +15,15 @@
*/
class Version1100Date20210304143008 extends SimpleMigrationStep {

/**
* @var TagMapper
*/
protected $tagMapper;

public function __construct(\OCA\Mail\Db\TagMapper $tagMapper) {
$this->tagMapper = $tagMapper;
}

/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
Expand All @@ -36,7 +46,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
'length' => 4,
]);
$tagsTable->addColumn('user_id', 'string', [
'notnull' => true,
'notnull' => false,
'length' => 64,
]);
$tagsTable->addColumn('imap_label', 'string', [
Expand All @@ -51,8 +61,21 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
$tagsTable->addColumn('color', 'string', [
'notnull' => false,
'length' => 9,
'default' => "#fff"
]);
$tagsTable->addColumn('is_system_flag', 'boolean', [
'notnull' => false,
'default' => false
]);
$tagsTable->setPrimaryKey(['id']);
$tagsTable->addIndex(['user_id'], 'mail_msg_tags_usr_id_index');
$tagsTable->addUniqueIndex(
[
'user_id',
'imap_label',
],
'mail_msg_tags_usr_lbl_idx'
);
}

if (!$schema->hasTable('mail_message_tags')) {
Expand All @@ -73,7 +96,6 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
$tagsMessageTable->setPrimaryKey(['id']);
}
return $schema;

}

/**
Expand All @@ -83,8 +105,31 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
*/
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
// add default labels here?
for( $i = 1; $i > 6; $i++) {
$tag = new \OCA\Mail\Db\Tag();
$tag->setImapLabel('$label' . $i);
switch( $i ) {
case 1:
$tag->setDisplayName('Important');
$tag->setColor('#FF0000');
case 2:
$tag->setDisplayName('Work');
$tag->setColor('#FFC300');
case 3:
$tag->setDisplayName('Personal');
$tag->setColor('#008000');
case 4:
$tag->setDisplayName('To Do');
$tag->setColor('#000080');
case 4:
$tag->setDisplayName('Later');
$tag->setColor('#800080');
}
$this->tagMapper->insert($tag);
}
// if server doesn't support IMAP PERFLAGS move all flags tagged as important to tags table here
// reset cache
// rewrite $important tag for each message after cache has been resynced
// Force a re-sync, so the values are propagated ASAP
}
}
Loading

0 comments on commit 38fed03

Please sign in to comment.