Commit a9deecc9 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

default is now stable

--HG--
branch : stable
......@@ -10,3 +10,5 @@ c65e11b67dc4438f9b36023612c8edcdede9a438 cubicweb-email-version-1_5_1
7b237859f2d2617fbebd00f19ca53f77890f89b4 cubicweb-email-version-1.6.0
d464f813a405376ea3fae96b5abd277a213532b0 cubicweb-email-debian-version-1.6.0-1
bb7aa8c654a45f401d7755b003ac69a5603d8f76 oldstable
22ec2b47db4aff2a92b3038f7f6069eb9cf5936a cubicweb-email-version-1.7.0
688fc001f03e6a52674fee6d70abacf17575f5c0 cubicweb-email-debian-version-1.7.0-1
......@@ -4,11 +4,11 @@
modname = 'email'
distname = "cubicweb-%s" % modname
numversion = (1, 6, 0)
numversion = (1, 7, 0)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL'
copyright = '''Copyright (c) 2003-2009 LOGILAB S.A. (Paris, FRANCE).
copyright = '''Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
http://www.logilab.fr/ -- mailto:contact@logilab.fr'''
author = "Logilab"
......@@ -44,11 +44,10 @@ except OSError:
# we are in an installed directory
pass
cube_eid = 20324
# used packages
__depends_cubes__ = {'file': '>= 1.6.0',}
__use__ = tuple(__depends_cubes__)
__depends__ = {'cubicweb': '>= 3.5.0'}
__depends__ = {'cubicweb': '>= 3.6.0'}
for key, value in __depends_cubes__.items():
__depends__['cubicweb-'+key] = value
__recommend__ = ('comment',)
......
cubicweb-email (1.7.0-1) unstable; urgency=low
* new upstream release
-- Sylvain Thénault <sylvain.thenault@logilab.fr> Tue, 09 Feb 2010 08:45:55 +0100
cubicweb-email (1.6.0-1) unstable; urgency=low
* new upstream release
......
......@@ -9,7 +9,7 @@ Homepage: http://www.cubicweb.org/project/cubicweb-email
Package: cubicweb-email
Architecture: all
Depends: cubicweb-common (>= 3.5.0), cubicweb-file (>= 1.6.0)
Depends: cubicweb-common (>= 3.6.0), cubicweb-file (>= 1.6.0)
Description: email component for the CubicWeb framework
This CubicWeb component models email messages.
.
......
......@@ -11,7 +11,7 @@ import re
from logilab.common import umessage
from cubicweb.interfaces import ITree
from cubicweb.common.mixins import TreeMixIn
from cubicweb.mixins import TreeMixIn
from cubicweb.entities import AnyEntity, fetch_config
from cubes.email.emailcites import parse_body
......@@ -19,7 +19,7 @@ from cubes.email.emailcites import parse_body
class Email(TreeMixIn, AnyEntity):
"""customized class for Email entities"""
id = 'Email'
__regid__ = 'Email'
fetch_attrs, fetch_order = fetch_config(['subject'])
__implements__ = AnyEntity.__implements__ + (ITree,)
......@@ -100,11 +100,11 @@ class Email(TreeMixIn, AnyEntity):
class EmailPart(AnyEntity):
"""customized class for EmailPart entities"""
id = 'EmailPart'
__regid__ = 'EmailPart'
def dc_title(self):
return '%s (%s %s)' % (self.email.subject,
self.req._('part'), self.ordernum)
self._cw._('part'), self.ordernum)
@property
def email(self):
......@@ -126,7 +126,7 @@ class EmailPart(AnyEntity):
class EmailThread(AnyEntity):
"""customized class for EmailThread entities"""
id = 'EmailThread'
__regid__ = 'EmailThread'
fetch_attrs, fetch_order = fetch_config(['title'])
def dc_title(self):
......
......@@ -13,9 +13,9 @@ __docformat__ = "restructuredtext en"
from logilab.mtconverter import TransformError
from cubicweb import UnknownEid, typed_eid
from cubicweb.server.pool import PreCommitOperation
from cubicweb.server.hooksmanager import Hook
from cubicweb.common.mail import parse_message_id
from cubicweb.mail import parse_message_id
from cubicweb.selectors import implements
from cubicweb.server import hook
def fix_ownership(session, eid, email):
......@@ -29,7 +29,7 @@ def fix_ownership(session, eid, email):
{'x': eid, 'u': sender.eid}, 'x')
class ExtractEmailInformation(PreCommitOperation):
class ExtractEmailInformation(hook.Operation):
"""generate a comment on the original entity if supported"""
def precommit_event(self):
......@@ -42,8 +42,8 @@ class ExtractEmailInformation(PreCommitOperation):
except UnknownEid:
self.error('email %s is referencing an unknown eid %s',
email.messageid, origeid)
return
if origetype in self.schema.rschema('comments').objects('Comment'):
return
if origetype in self.session.vreg.schema['comments'].objects('Comment'):
try:
part = email.parts_in_order(prefered_mime_type='text/plain')[0]
except IndexError:
......@@ -65,7 +65,7 @@ class ExtractEmailInformation(PreCommitOperation):
fix_ownership(self.session, com[0][0], self.email)
class AnalyzeEmailText(PreCommitOperation):
class AnalyzeEmailText(hook.Operation):
"""check if there are some change state instruction in the mail content"""
def precommit_event(self):
......@@ -85,19 +85,20 @@ class AnalyzeEmailText(PreCommitOperation):
fix_ownership(self.session, evargs['trinfo'].eid, self.email)
class AddEmailHook(Hook):
class AddEmailHook(hook.Hook):
"""an email has been added, check if associated content should be created
"""
__regid__ = 'extractmailcontent'
__select__ = hook.Hook.__select__ & implements('Email')
events = ('after_add_entity',)
accepts = ('Email',)
def call(self, session, entity):
if 'comments' in session.repo.schema:
for msgid in entity.references():
info = parse_message_id(msgid, self.config.appid)
def __call__(self):
if 'comments' in self._cw.repo.schema:
for msgid in self.entity.references():
info = parse_message_id(msgid, self._cw.vreg.config.appid)
self.info('extracted information from message id %s: %s',
msgid, info)
if info:
ExtractEmailInformation(session, email=entity, info=info)
ExtractEmailInformation(self._cw, email=self.entity, info=info)
break
AnalyzeEmailText(session, email=entity)
AnalyzeEmailText(self._cw, email=self.entity)
......@@ -40,7 +40,7 @@ class Email(EntityType):
class EmailPart(EntityType):
"""an email attachment"""
permissions = {
__permissions__ = {
'read': ('managers', 'users', 'guests',), # XXX if E parts X, U has_read_permission E
'add': ('managers', ERQLExpression('E parts X, U has_update_permission E'),),
'delete': ('managers', ERQLExpression('E parts X, U has_update_permission E')),
......@@ -50,7 +50,7 @@ class EmailPart(EntityType):
content = String(fulltextindexed=True)
content_format = String(required=True, meta=True, maxsize=50)
ordernum = Int(required=True)
alternative = SubjectRelation('EmailPart', symetric=True)
alternative = SubjectRelation('EmailPart', symmetric=True)
class EmailThread(EntityType):
......
......@@ -4,7 +4,7 @@ from StringIO import StringIO
from logilab.common.testlib import unittest_main
from cubicweb.devtools.apptest import EnvBasedTC
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.common.mail import construct_message_id
MSG = u'''From sthenault@free.fr Tue Jan 23 15:21:10 2007
......@@ -39,11 +39,11 @@ Content-Length: 122
Lines: 2
'''
class ChangeStateHooksTC(EnvBasedTC):
class ChangeStateHooksTC(CubicWebTC):
def setup_database(self):
self.add_entity('BlogEntry', title=u"une news !", content=u"cubicweb c'est beau")
self.add_entity('EmailAddress', address=u'devel@logilab.fr', alias=u'devel')
self.request().create_entity('BlogEntry', title=u"une news !", content=u"cubicweb c'est beau")
self.request().create_entity('EmailAddress', address=u'devel@logilab.fr', alias=u'devel')
self.msg = MSG % (self.vreg.config.appid, gethostname())
......@@ -140,15 +140,15 @@ hop
from cubes.email.mboximport import MBOXImporter
class ReplyCommentHooksTC(EnvBasedTC):
class ReplyCommentHooksTC(CubicWebTC):
def setup_database(self):
self.b = self.add_entity('BlogEntry', title=u"une news !", content=u"cubicweb c'est beau")
e = self.add_entity('EmailAddress', address=u'sylvain.thenault@logilab.fr', alias=u'syt')
self.b = self.request().create_entity('BlogEntry', title=u"une news !", content=u"cubicweb c'est beau")
e = self.request().create_entity('EmailAddress', address=u'sylvain.thenault@logilab.fr', alias=u'syt')
self.execute('SET X use_email E WHERE X login "anon", E eid %(e)s', {'e': e.eid})
def test_comment_created(self):
mi = MBOXImporter(self.env.cnx)
mi = MBOXImporter(self.cnx)
msg = open('data/reply.mbox', 'rb').read() % \
construct_message_id(self.vreg.config.appid, self.b.eid, False)
mi.import_mbox_stream(StringIO(msg))
......
......@@ -4,15 +4,15 @@ from StringIO import StringIO
from logilab.common.testlib import TestCase, unittest_main
from cubicweb.devtools.apptest import EnvBasedTC
from cubicweb.devtools.testlib import CubicWebTC
from cubes.email.mboximport import MBOXImporter
class MBOXImporterTC(EnvBasedTC):
class MBOXImporterTC(CubicWebTC):
def test_all(self):
mi = MBOXImporter(self.env.cnx)
mi = MBOXImporter(self.cnx)
mi.import_mbox_stream(open('data/mbox'))
self.assertEquals(sorted([(x, len(y)) for x, y in mi.created.items()]),
[('email', 2), ('emailaddress', 4),
......@@ -174,7 +174,7 @@ http://lists.logilab.org/mailman/listinfo/python-projects
"""
def test_no_subject(self):
mi = MBOXImporter(self.env.cnx)
mi = MBOXImporter(self.cnx)
mi.import_mbox_stream(StringIO(self.NOSUBJECT))
rset = self.execute('Any X ORDERBY S WHERE X is Email, X subject S')
self.assertEquals(len(rset), 1)
......@@ -183,7 +183,7 @@ http://lists.logilab.org/mailman/listinfo/python-projects
self.assertEquals(email.references(), set(('<xxx@blabla>',)))
def test_double_import(self):
mi = MBOXImporter(self.env.cnx)
mi = MBOXImporter(self.cnx)
mi.import_mbox_stream(StringIO(self.NOSUBJECT))
mi.import_mbox_stream(StringIO(self.NOSUBJECT))
rset = self.execute('Any X ORDERBY S WHERE X is Email, X subject S')
......@@ -203,7 +203,7 @@ http://lists.logilab.org/mailman/listinfo/python-projects
#self.assertEquals(testrset[0][0], eid2)
#testrset = cursor.execute('Any X WHERE X identical_to Y, X canonical TRUE, Y eid %(y)s', {'y': eid1})
#self.assertEquals(testrset[0][0], eid2)
mi = MBOXImporter(self.env.cnx)
mi = MBOXImporter(self.cnx)
mi.import_mbox_stream(StringIO(self.NOSUBJECT))
rset = self.execute('Any X ORDERBY S WHERE X is Email, X subject S')
self.assertEquals(len(rset), 1)
......
......@@ -10,8 +10,8 @@ _ = unicode
from logilab.mtconverter import xml_escape
from cubicweb.selectors import implements
from cubicweb.common.uilib import soup2xhtml
from cubicweb.common.mixins import TreeViewMixIn
from cubicweb.uilib import soup2xhtml
from cubicweb.mixins import TreeViewMixIn
from cubicweb.web import uicfg, formwidgets
from cubicweb.web.views import baseviews, primary
......@@ -34,8 +34,8 @@ def formated_sender(email):
# sender address has been removed, look in email's headers
message = email.umessage_headers()
if message:
return xml_escape(message.get('From'))
return email.req._('unknown sender')
return xml_escape(message.get('From', ''))
return email._cw._('unknown sender')
class EmailPrimaryView(primary.PrimaryView):
__select__ = implements('Email')
......@@ -43,21 +43,21 @@ class EmailPrimaryView(primary.PrimaryView):
def render_entity_attributes(self, entity):
self.w(u'<div class="emailheader"><table>')
self.w(u'<tr><td>%s</td><td>%s</td></tr>' %
(self.req._('From'), formated_sender(entity)))
(self._cw._('From'), formated_sender(entity)))
self.w(u'<tr><td>%s</td><td>%s</td></tr>' %
(self.req._('To'), ', '.join(ea.view('oneline') for ea in entity.recipients)))
(self._cw._('To'), ', '.join(ea.view('oneline') for ea in entity.recipients)))
if entity.cc:
self.w(u'<tr><td>%s</td><td>%s</td></tr>' %
(self.req._('CC'), ', '.join(ea.view('oneline') for ea in entity.cc)))
(self._cw._('CC'), ', '.join(ea.view('oneline') for ea in entity.cc)))
self.w(u'<tr><td>%s</td><td>%s</td></tr>' %
(self.req._('Date'), self.format_date(entity.date, time=True)))
(self._cw._('Date'), self._cw.format_date(entity.date, time=True)))
self.w(u'<tr><td>%s</td><td>%s</td></tr>' %
(self.req._('Subject'), xml_escape(entity.subject)))
(self._cw._('Subject'), xml_escape(entity.subject)))
self.w(u'</table></div><div class="emailcontent">')
for part in entity.parts_in_order():
content, mime = part.content, part.content_format
if mime == 'text/html':
content = soup2xhtml(content, self.req.encoding)
content = soup2xhtml(content, self._cw.encoding)
elif mime != 'text/xhtml':
content = xml_escape(content)
if mime == 'text/plain':
......@@ -74,14 +74,14 @@ class EmailPrimaryView(primary.PrimaryView):
class EmailHeadersView(baseviews.EntityView):
"""display email's headers"""
id = 'headers'
__regid__ = 'headers'
__select__ = implements('Email')
title = _('headers')
templatable = False
content_type = 'text/plain'
def cell_call(self, row, col):
entity = self.entity(row, col)
entity = self.cw_rset.get_entity(row, col)
self.w(entity.headers)
......@@ -93,18 +93,18 @@ class EmailOneLineView(baseviews.OneLineView):
title = _('oneline')
def cell_call(self, row, col, contexteid=None):
entity = self.entity(row, col)
entity = self.cw_rset.get_entity(row, col)
self.w(u'<div class="email">')
self.w(u'<i>%s&nbsp;%s</i> ' % (
self.req._('email_date'), self.format_date(entity.date, time=True)))
self._cw._('email_date'), self._cw.format_date(entity.date, time=True)))
sender = entity.senderaddr
if sender is None or contexteid != sender.eid:
self.w(u'<b>%s</b>&nbsp;%s '
% (self.req._('email_from'), formated_sender(entity)))
% (self._cw._('email_from'), formated_sender(entity)))
if contexteid not in (r.eid for r in entity.recipients):
recipients = ', '.join(r.view('oneline') for r in entity.recipients)
self.w(u'<b>%s</b>&nbsp;%s'
% (self.req._('email_to'), recipients))
% (self._cw._('email_to'), recipients))
self.w(u'<br/>\n<a href="%s">%s</a>' % (
xml_escape(entity.absolute_url()), xml_escape(entity.subject)))
self.w(u'</div>')
......@@ -112,20 +112,20 @@ class EmailOneLineView(baseviews.OneLineView):
class EmailOutOfContextView(EmailOneLineView):
"""short view outside the context of the email"""
id = 'outofcontext'
__regid__ = 'outofcontext'
title = _('out of context')
class EmailInContextView(EmailOneLineView):
"""short view inside the context of the email"""
id = 'incontext'
__regid__ = 'incontext'
class EmailPartOutOfContextView(baseviews.OutOfContextView):
"""out of context an email part is redirecting to related email view"""
__select__ = implements('EmailPart')
def cell_call(self, row, col):
entity = self.entity(row, col)
entity = self.cw_rset.get_entity(row, col)
entity.reverse_parts[0].view('outofcontext', w=self.w)
......@@ -141,7 +141,7 @@ class EmailThreadPrimaryView(primary.PrimaryView):
__select__ = implements('EmailThread')
def cell_call(self, row, col):
entity = self.complete_entity(row, col)
entity = self.cw_rset.complete_entity(row, col)
self.w(u'<h1>%s</h1>' % xml_escape(entity.title))
# get top level emails in this thread (ie message which are not a reply
# of a message in this thread)
......@@ -155,7 +155,7 @@ class EmailThreadPrimaryView(primary.PrimaryView):
# NOT Y in_thread E, E eid %(x)s'
# to get message which are a reply of a message in another thread ?
# we may get duplicates in this case
rset = self.req.execute('DISTINCT Any X,D ORDERBY D '
rset = self._cw.execute('DISTINCT Any X,D ORDERBY D '
'WHERE X date D, X in_thread E, '
'NOT X reply_to Y, E eid %(x)s',
{'x': entity.eid}, 'x')
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment