summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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; },