summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuda Dornelles <ddornell@thoughtworks.com>2014-10-16 13:53:16 +0200
committerDuda Dornelles <ddornell@thoughtworks.com>2014-10-16 13:54:03 +0200
commit0de9d8dc31298921f7272d74cdd3c5d4217b5841 (patch)
tree468ba5005379151eff72c5aaaf37db9ba29b3ef7
parent761e85e523ec61f5629a9f1f6e4196e23ce96673 (diff)
decreasing count on tag and tag shortcut when email is read. we were
decreasing only tags that were also in the read mail, but we have also to look at the mailbox and compare that to the tags in the case of default tags #95
-rw-r--r--service/pixelated/adapter/mail.py7
-rw-r--r--service/pixelated/adapter/mail_service.py3
-rw-r--r--service/pixelated/controllers/mails_controller.py7
-rw-r--r--service/test/unit/adapter/mail_test.py24
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js3
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/mail_item.js3
-rw-r--r--web-ui/app/js/tags/ui/tag.js6
-rw-r--r--web-ui/app/js/tags/ui/tag_list.js4
-rw-r--r--web-ui/app/js/tags/ui/tag_shortcut.js29
-rw-r--r--web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js8
-rw-r--r--web-ui/test/spec/tags/ui/tag.spec.js51
-rw-r--r--web-ui/test/test_data.js3
12 files changed, 113 insertions, 35 deletions
diff --git a/service/pixelated/adapter/mail.py b/service/pixelated/adapter/mail.py
index 513a07d8..5cafa36a 100644
--- a/service/pixelated/adapter/mail.py
+++ b/service/pixelated/adapter/mail.py
@@ -52,6 +52,10 @@ class Mail:
return self.fdoc.content.get('flags')
@property
+ def mailbox_name(self):
+ return self.fdoc.content.get('mbox')
+
+ @property
def _mime_multipart(self):
if self._mime:
return self._mime
@@ -75,7 +79,8 @@ class Mail:
'tags': list(self.tags),
'status': list(self.status),
'security_casing': {},
- 'body': self.body
+ 'body': self.body,
+ 'mailbox': self.mailbox_name.lower()
}
diff --git a/service/pixelated/adapter/mail_service.py b/service/pixelated/adapter/mail_service.py
index e908feb7..cc03ab3a 100644
--- a/service/pixelated/adapter/mail_service.py
+++ b/service/pixelated/adapter/mail_service.py
@@ -35,7 +35,8 @@ class MailService:
if len(reserved_words):
raise ValueError('None of the following words can be used as tags: ' + ' '.join(reserved_words))
mail = self.mail(mail_id)
- return mail.update_tags(set(new_tags))
+ mail.update_tags(set(new_tags))
+ return mail
def mail(self, mail_id):
return self.mailboxes.mail(mail_id)
diff --git a/service/pixelated/controllers/mails_controller.py b/service/pixelated/controllers/mails_controller.py
index 6bd2fe99..f6414f27 100644
--- a/service/pixelated/controllers/mails_controller.py
+++ b/service/pixelated/controllers/mails_controller.py
@@ -92,11 +92,12 @@ class MailsController:
def mail_tags(self, mail_id):
new_tags = map(lambda tag: tag.lower(), request.get_json()['newtags'])
try:
- tags = self._mail_service.update_tags(mail_id, new_tags)
- self._search_engine.index_mail(self._mail_service.mail(mail_id))
+ self._mail_service.update_tags(mail_id, new_tags)
+ mail = self._mail_service.mail(mail_id)
+ self._search_engine.index_mail(mail)
except ValueError as ve:
return respond_json(ve.message, 403)
- return respond_json(list(tags))
+ return respond_json(mail.as_dict())
def update_draft(self):
_mail = InputMail.from_dict(request.json)
diff --git a/service/test/unit/adapter/mail_test.py b/service/test/unit/adapter/mail_test.py
index 20038e96..94578a05 100644
--- a/service/test/unit/adapter/mail_test.py
+++ b/service/test/unit/adapter/mail_test.py
@@ -19,10 +19,10 @@ import pixelated.support.date
from pixelated.adapter.mail import PixelatedMail, InputMail
from mockito import *
from test.support import test_helper
+import dateutil.parser as dateparser
class TestPixelatedMail(unittest.TestCase):
-
def setUp(self):
self.querier = mock()
@@ -68,6 +68,28 @@ class TestPixelatedMail(unittest.TestCase):
self.assertEquals(mail.fdoc.content['flags'], [])
+ def test_as_dict(self):
+ fdoc, hdoc, bdoc = test_helper.leap_mail(flags=['\\Recent'])
+ hdoc.content['headers']['Subject'] = 'The subject'
+ hdoc.content['headers']['From'] = 'me@pixelated.org'
+
+ mail = PixelatedMail.from_soledad(fdoc, hdoc, bdoc, soledad_querier=self.querier)
+
+ _dict = mail.as_dict()
+
+ self.assertEquals(_dict, {'body': 'body',
+ 'header': {
+ 'date': dateparser.parse(hdoc.content['date']).isoformat(),
+ 'from': 'me@pixelated.org',
+ 'subject': 'The subject'
+ },
+ 'ident': 'chash',
+ 'mailbox': 'inbox',
+ 'security_casing': {},
+ 'status': ['recent'],
+ 'tags': []}
+ )
+
class InputMailTest(unittest.TestCase):
mail_dict = lambda x: {
diff --git a/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js
index 3d426447..d5dfbf28 100644
--- a/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js
@@ -51,7 +51,8 @@ define(
function updateMailStatusToRead() {
if (!_.contains(this.attr.mail.status, this.status.READ)) {
- this.trigger(document, events.mail.read, { ident: this.attr.ident, tags: this.attr.mail.tags });
+ var mail_read_data = { ident: this.attr.ident, tags: this.attr.tags, mailbox: this.attr.mailbox };
+ this.trigger(document, events.mail.read, mail_read_data);
this.attr.mail.status.push(this.status.READ);
this.$node.addClass(viewHelpers.formatStatusClasses(this.attr.mail.status));
}
diff --git a/web-ui/app/js/mail_list/ui/mail_items/mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js
index 5a4192e6..5f1f354a 100644
--- a/web-ui/app/js/mail_list/ui/mail_items/mail_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014 ThoughtWorks, Inc.
- *
+ *
* Pixelated 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
@@ -64,6 +64,7 @@ define(
this.attr.ident = mail.ident;
this.attr.statuses = viewHelper.formatStatusClasses(mail.status);
this.attr.tags = mail.tags;
+ this.attr.mailbox = mail.mailbox;
this.attr.header.formattedDate = this.formattedDate(mail.header.date);
};
diff --git a/web-ui/app/js/tags/ui/tag.js b/web-ui/app/js/tags/ui/tag.js
index c2b7f588..2cf45764 100644
--- a/web-ui/app/js/tags/ui/tag.js
+++ b/web-ui/app/js/tags/ui/tag.js
@@ -52,9 +52,13 @@ define(
};
this.decreaseReadCountIfMatchingTag = function (ev, data) {
- if (_.contains(data.tags, this.attr.tag.name)) {
+ var mailbox_and_tags = _.flatten([data.tags, data.mailbox]);
+ if (_.contains(mailbox_and_tags, this.attr.tag.name)) {
this.attr.tag.counts.read++;
this.$node.html(this.viewFor(this.attr.tag, templates.tags.tagInner));
+ if (!_.isUndefined(this.attr.shortcut)) {
+ this.attr.shortcut.reRender();
+ }
}
};
diff --git a/web-ui/app/js/tags/ui/tag_list.js b/web-ui/app/js/tags/ui/tag_list.js
index 5bbac8ca..b5b4d555 100644
--- a/web-ui/app/js/tags/ui/tag_list.js
+++ b/web-ui/app/js/tags/ui/tag_list.js
@@ -55,7 +55,7 @@ define(
});
this.renderShortcut = function (tag, tagComponent) {
- TagShortcut.appendedTo($('#tags-shortcuts'), { linkTo: tag, trigger: tagComponent});
+ return TagShortcut.appendedTo($('#tags-shortcuts'), { linkTo: tag, trigger: tagComponent});
};
function renderTag(tag, defaultList, customList) {
@@ -63,7 +63,7 @@ define(
var tagComponent = Tag.appendedTo(list, {tag: tag});
if (_.contains(_.keys(ORDER), tag.name)) {
- this.renderShortcut(tag, tagComponent);
+ tagComponent.attr.shortcut = this.renderShortcut(tag, tagComponent);
}
}
diff --git a/web-ui/app/js/tags/ui/tag_shortcut.js b/web-ui/app/js/tags/ui/tag_shortcut.js
index 5710592e..0fe92550 100644
--- a/web-ui/app/js/tags/ui/tag_shortcut.js
+++ b/web-ui/app/js/tags/ui/tag_shortcut.js
@@ -26,7 +26,7 @@ define(
function (describeComponent, templates, events, tagBase, utils) {
- var TagShortcut = describeComponent(tagShortcut, tagBase);
+ var TagShortcut = describeComponent(tagShortcut, tagBase);
TagShortcut.appendedTo = function (parent, data) {
var res = new this();
@@ -38,9 +38,7 @@ define(
function tagShortcut() {
- this.renderAndAttach = function (parent, options) {
- var linkTo = options.linkTo;
-
+ this.renderTemplate = function (linkTo) {
var model = {
tagName: linkTo.name,
displayBadge: this.displayBadge(linkTo),
@@ -48,11 +46,16 @@ define(
count: this.badgeType(linkTo) === 'total' ? linkTo.counts.total : (linkTo.counts.total - linkTo.counts.read),
icon: iconFor[linkTo.name]
};
+ return templates.tags.shortcut(model);
+ };
- var rendered = templates.tags.shortcut(model);
- parent.append(rendered);
+ this.renderAndAttach = function (parent, options) {
+ parent.append(this.renderTemplate(options.linkTo));
+ this.initialize(parent.children().last(), options);
+ };
- this.initialize(parent.children().last(),options);
+ this.reRender = function () {
+ this.$node.html(this.renderTemplate(this.attr.linkTo));
};
var iconFor = {
@@ -64,8 +67,12 @@ define(
};
this.selectTag = function (ev, data) {
- if(data.tag === this.attr.linkTo.name) { this.doSelect(); }
- else { this.doUnselect(); }
+ if (data.tag === this.attr.linkTo.name) {
+ this.doSelect();
+ }
+ else {
+ this.doUnselect();
+ }
};
this.doUnselect = function () {
@@ -83,7 +90,9 @@ define(
};
this.after('initialize', function () {
- this.on('click', function () { this.attr.trigger.triggerSelect(); });
+ this.on('click', function () {
+ this.attr.trigger.triggerSelect();
+ });
this.on(document, events.ui.tag.select, this.selectTag);
this.on(document, events.tags.shortcuts.teardown, this.doTeardown);
});
diff --git a/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js b/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js
index ecb2b854..b03babb5 100644
--- a/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js
+++ b/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js
@@ -5,7 +5,8 @@ describeComponent('mail_list/ui/mail_items/generic_mail_item', function () {
beforeEach(function () {
mail = Pixelated.testData().parsedMail.simpleTextPlain;
- mail.tags = ['inbox'];
+ mail.tags = [];
+ mail.mailbox = 'inbox';
setupComponent('<li></li>', {
mail: mail,
@@ -95,7 +96,7 @@ describeComponent('mail_list/ui/mail_items/generic_mail_item', function () {
expect(this.component.attr.mail.status).toContain(this.component.status.READ);
expect(this.$node.attr('class')).toMatch('status-read');
- expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, { ident: mail.ident, tags: ['inbox'] });
+ expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, { ident: mail.ident, tags: [], mailbox: 'inbox' });
});
});
@@ -110,7 +111,8 @@ describeComponent('mail_list/ui/mail_items/generic_mail_item', function () {
this.$node.find('a').click();
- expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ident: mail.ident}));
+ var expectedEventData = {ident: mail.ident};
+ expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining(expectedEventData));
});
it('should not trigger mail:read event when clicking mail that is already read', function () {
diff --git a/web-ui/test/spec/tags/ui/tag.spec.js b/web-ui/test/spec/tags/ui/tag.spec.js
index de78ba75..48f761da 100644
--- a/web-ui/test/spec/tags/ui/tag.spec.js
+++ b/web-ui/test/spec/tags/ui/tag.spec.js
@@ -4,7 +4,7 @@
describeComponent('tags/ui/tag', function () {
'use strict';
- describe('inbox tag', function() {
+ describe('inbox tag', function () {
beforeEach(function () {
setupComponent('<li></li>', {
tag: {
@@ -46,11 +46,42 @@ describeComponent('tags/ui/tag', function () {
expect(tagSelectedEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'drafts'});
});
- it('increases the read count when there is an email read and the email has that tag', function () {
+ describe('increasing count read when email is read', function () {
+ it('doesnt update if mail.tags or mail.mailbox dont match the tag name', function () {
+ setupComponent('<li></li>', {
+ tag: { name: 'sometag', ident: '1', counts: { total: 100, read: 0 } }
+ });
+
+ $(document).trigger(Pixelated.events.mail.read, { tags: ['someothertag'], mailbox: 'inbox' });
+
+ expect(this.component.attr.tag.counts.read).toEqual(0);
+ });
+
+ it('looks at the mail mailbox attr for default tags', function () {
+ $(document).trigger(Pixelated.events.mail.read, { tags: [], mailbox: 'inbox' });
+
+ expect(this.component.attr.tag.counts.read).toEqual(1);
+ expect(this.$node.html()).toMatch('<span class="unread-count">99</span>');
+ });
+
+ it('looks at the mail tags for non default tags', function () {
+ setupComponent('<li></li>', {
+ tag: { name: 'tag', ident: '1', counts: { total: 100, read: 0 } }
+ });
+
+ $(document).trigger(Pixelated.events.mail.read, { tags: ['tag'], mailbox: 'inbox' });
+
+ expect(this.component.attr.tag.counts.read).toEqual(1);
+ expect(this.$node.html()).toMatch('<span class="unread-count">99</span>');
+ });
+ });
+
+ it('re-renders the tag shortcut linked to it when increasing the read count if there is a shortcut', function () {
+ this.component.attr.shortcut = jasmine.createSpyObj('shortcut', ['reRender']);
+
$(document).trigger(Pixelated.events.mail.read, { tags: ['inbox'] });
- expect(this.component.attr.tag.counts.read).toEqual(1);
- expect(this.$node.html()).toMatch('<span class="unread-count">99</span>');
+ expect(this.component.attr.shortcut.reRender).toHaveBeenCalled();
});
it('doesnt increase the read count when the read email doesnt have the tag', function () {
@@ -89,7 +120,7 @@ describeComponent('tags/ui/tag', function () {
});
});
- describe('all tag', function(){
+ describe('all tag', function () {
beforeEach(function () {
setupComponent('<li></li>', {
tag: {
@@ -103,18 +134,18 @@ describeComponent('tags/ui/tag', function () {
});
});
- it('adds searching class when user is doing a search', function(){
+ it('adds searching class when user is doing a search', function () {
$(document).trigger(Pixelated.events.search.perform, {});
expect(this.$node.attr('class')).toMatch('searching');
});
- it('removes searching class when user searches for empty string', function(){
+ it('removes searching class when user searches for empty string', function () {
$(document).trigger(Pixelated.events.search.perform, {});
$(document).trigger(Pixelated.events.search.empty);
expect(this.$node.attr('class')).not.toMatch('searching');
});
- it('removes searching class when user clicks in any tag', function(){
+ it('removes searching class when user clicks in any tag', function () {
$(document).trigger(Pixelated.events.search.perform, {});
this.$node.click();
expect(this.$node.attr('class')).not.toMatch('searching');
@@ -122,8 +153,8 @@ describeComponent('tags/ui/tag', function () {
});
- _.each(['sent', 'trash'], function(tag_name) {
- describe(tag_name + ' tag', function() {
+ _.each(['sent', 'trash'], function (tag_name) {
+ describe(tag_name + ' tag', function () {
beforeEach(function () {
setupComponent('<li></li>', {
tag: {
diff --git a/web-ui/test/test_data.js b/web-ui/test/test_data.js
index bf3626bb..194cd02d 100644
--- a/web-ui/test/test_data.js
+++ b/web-ui/test/test_data.js
@@ -84,7 +84,8 @@ define(function() {
date:'2014-06-04T14:41:13-03:00'
},
ident:1,
- tags:['textplain','inbox'],
+ tags:['textplain'],
+ mailbox: ['inbox'],
status:[],
body: 'Hello Everyone',
isSentMail: function() { return false; },