Commit c17935f1 authored by Laurent Peuch's avatar Laurent Peuch
Browse files

fix: backport missing work from pypi

parent e05d6bc70adc
Pipeline #140437 failed with stages
in 35 seconds
include *.py
include views/*.py
include bin/*
include cubicweb-email.spec
recursive-include data external_resources *.gif
recursive-include i18n *.pot *.po
recursive-include migration *.py
recursive-include views *.py
recursive-include doc *.txt *.html
exclude test/data/database/*
include requirements-test.txt
include tox.ini
include README.rst
exclude .cube-doctor.yml
exclude .gitlab-ci.yml
exclude .gitlab-ci-extended.yml
exclude .yamllint
include */*.py
include *requirements.txt
recursive-include cubicweb_email *.py
recursive-include cubicweb_email/data *.gif *.png *.ico *.css *.js
recursive-include cubicweb_email/i18n *.po
recursive-include cubicweb_email/wdoc *
recursive-include test/data bootstrap_cubes *.py
recursive-include test/data/maildir/cur *,S
include test/data/*mbox
include *.ini
prune cubicweb-email.spec
prune debian
Metadata-Version: 1.1
Name: cubicweb-email
Version: 1.13.1
Summary: email component for the CubicWeb framework
Home-page: http://www.cubicweb.org/project/cubicweb-email
Author: Logilab
Author-email: contact@logilab.fr
License: LGPL
Description: This cube models multipart email messages (`Emails` and `EmailPart`) and
provides tools to import your mail box into a cubicweb instance.
Email are automatically stored into`EmailThreads`.
It also comes with a command line tool to import emails (mbox) files
in a CubicWeb instance. This tool is based on cwclientlib_, so
connection credentials to the cubicweb instance should be stored in
your ~/.config/cwclientlibrc file.
.. _cwclientlib: https://www.cubicweb.org/project/cwclientlib
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Framework :: CubicWeb
Classifier: Programming Language :: Python
Classifier: Programming Language :: JavaScript
# pylint: disable-msg=W0622
"""cubicweb-email packaging information"""
modname = 'email'
distname = "cubicweb-%s" % modname
numversion = (1, 12, 0)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL'
author = "Logilab"
author_email = "contact@logilab.fr"
web = 'https://forge.extranet.logilab.fr/cubicweb/cubes/%s' % distname
description = "email component for the CubicWeb framework"
classifiers = [
'Environment :: Web Environment',
'Framework :: CubicWeb',
'Programming Language :: Python',
'Programming Language :: JavaScript',
]
# used packages
__depends__ = {'cubicweb': ">= 3.20.0, < 3.32.0",
'cubicweb-file': '>= 1.9.0',
'logilab-common': '>= 0.58.3',
'cwclientlib': '>= 0.3.1',
}
__recommends__ = {'cubicweb-comment': None}
# packaging ###
from os import listdir as _listdir
from os.path import join, isdir
from glob import glob
THIS_CUBE_DIR = join('share', 'cubicweb', 'cubes', modname)
def listdir(dirpath):
return [join(dirpath, fname) for fname in _listdir(dirpath)
if fname[0] != '.' and not fname.endswith('.pyc')
and not fname.endswith('~')
and not isdir(join(dirpath, fname))]
data_files = [
# common files
[THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']],
]
# check for possible extended cube layout
for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration', 'wdoc'):
if isdir(dirname):
data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)])
# Note: here, you'll need to add subdirectories if you want
# them to be included in the debian package
scripts = ['bin/cw-mboximport']
packages = ['cwemail']
......@@ -2,4 +2,3 @@
from cwemail.mboximport import main
main()
# pylint: disable=W0622
"""cubicweb-email packaging information"""
modname = 'email'
distname = "cubicweb-%s" % modname
numversion = (1, 13, 1)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL'
author = "Logilab"
author_email = "contact@logilab.fr"
web = 'http://www.cubicweb.org/project/%s' % distname
description = "email component for the CubicWeb framework"
classifiers = [
'Environment :: Web Environment',
'Framework :: CubicWeb',
'Programming Language :: Python',
'Programming Language :: JavaScript',
]
__depends__ = {
'cubicweb': '>= 3.24',
'cubicweb-file': '>= 1.9.0',
'cwclientlib': '>= 0.3.1',
}
......@@ -21,31 +21,34 @@ def parse_body(body, quote='>'):
newlevel += 1
line = line[1:].lstrip()
if line.strip() == '--':
break # ignore following signature
break # ignore following signature
if newlevel != level:
# detect lines such as
# On Wed, Jan 23, 2008 at 06:48:22PM +0100, machin wrote:
# preceding citation
if not newlevel in seenlevels and res and res[-1][1] and \
res[-1][1][-1].rstrip().endswith(':'):
if (
newlevel not in seenlevels and res and res[-1][1]
and res[-1][1][-1].rstrip().endswith(':')
):
current.insert(0, res[-1][1].pop())
seenlevels.add(newlevel)
res.append( (level, current) )
res.append((level, current))
current = []
level = newlevel
current.append(line)
res.append( (level, current) )
res.append((level, current))
pmsg = ParsedMessage()
for level, lines in res:
para = ''.join(lines).strip()
if not para:
continue
if level > 0 :
if level > 0:
pmsg.cites.append(para)
else:
pmsg.content.append(para)
return pmsg
class ParsedMessage(object):
def __init__(self):
self.content = []
......@@ -54,6 +57,7 @@ class ParsedMessage(object):
@property
def actual_content(self):
return '\n'.join(self.content)
@property
def cited_content(self):
return '\n'.join(self.cites)
......
......@@ -13,7 +13,7 @@ from logilab.common import umessage
from cubicweb.entities import AnyEntity, fetch_config, adapters
from cubicweb.predicates import is_instance
from cubes.email.emailcites import parse_body
from cubicweb_email.emailcites import parse_body
class Email(AnyEntity):
......@@ -77,9 +77,9 @@ class Email(AnyEntity):
result.update(refs.split())
return result
lines_rgx = re.compile('^Lines:\s*\d+\s*\n', re.I|re.U|re.M)
clength_rgx = re.compile('^Content-Length:\s*\d+\s*\n', re.I|re.U|re.M)
ctype_rgx = re.compile('^Content-Type:[^:]', re.I|re.U|re.M)
lines_rgx = re.compile(r'^Lines:\s*\d+\s*\n', re.I | re.U | re.M)
clength_rgx = re.compile(r'^Content-Length:\s*\d+\s*\n', re.I | re.U | re.M)
ctype_rgx = re.compile(r'^Content-Type:[^:]', re.I | re.U | re.M)
def umessage_headers(self):
if not self.headers:
......@@ -87,8 +87,7 @@ class Email(AnyEntity):
headers = self.lines_rgx.sub('', self.headers)
headers = self.clength_rgx.sub('', headers)
headers = self.ctype_rgx.sub('Content-type: text/plain; charset=utf8', headers)
return umessage.message_from_string(headers + u'\n\n')
return umessage.message_from_string(headers + '\n\n')
class EmailPart(AnyEntity):
......@@ -141,4 +140,3 @@ class EmailPartIFTIAdapter(adapters.IFTIndexableAdapter):
return []
except AttributeError:
return super(EmailPartIFTIAdapter, self).get_words()
......@@ -27,9 +27,9 @@ def fix_ownership(cnx, eid, email):
if sender and sender.e_schema == 'CWUser' and sender.eid != cnx.user.eid:
# match a user which is not the connection's user, set owned_by / created_by
cnx.execute('SET X owned_by U WHERE X eid %(x)s, U eid %(u)s',
{'x': eid, 'u': sender.eid})
{'x': eid, 'u': sender.eid})
cnx.execute('SET X created_by U WHERE X eid %(x)s, U eid %(u)s',
{'x': eid, 'u': sender.eid})
{'x': eid, 'u': sender.eid})
class ExtractEmailInformation(hook.Operation):
......@@ -54,7 +54,7 @@ class ExtractEmailInformation(hook.Operation):
else:
try:
self.insert_comment(origeid, part)
except:
except Exception:
self.exception('while generating comment on %s from email %s',
origeid, email)
......@@ -107,7 +107,9 @@ class AddEmailCommentHook(hook.Hook):
AnalyzeEmailText(self._cw, email=self.entity)
CLEANUP_RGX = re.compile(r'\bre\s*:', re.I|re.U)
CLEANUP_RGX = re.compile(r'\bre\s*:', re.I | re.U)
def cleanup_subject(string):
return CLEANUP_RGX.sub('', string).strip()
......@@ -148,6 +150,8 @@ class AddEmailPreHook(hook.Hook):
message = UMessage(email.message_from_string(msg.headers))
except Exception:
self.exception('bad message headers')
if self._cw.repo.config.mode == 'test':
raise
return
# XXX why limit to a single sender?
if 'messageid' not in msg.cw_edited:
......@@ -157,9 +161,13 @@ class AddEmailPreHook(hook.Hook):
if 'date' not in msg.cw_edited:
msg.cw_edited['date'] = message.date()
if 'sender' not in msg.cw_edited:
sender = message.multi_addrs('from')[0]
sendereid = self.address_eid(sender[1], sender[0])
msg.cw_edited['sender'] = sendereid
try:
sender = message.multi_addrs('from')[0]
except IndexError:
pass
else:
sendereid = self.address_eid(sender[1], sender[0])
msg.cw_edited['sender'] = sendereid
replyto = message.get('in-reply-to')
if replyto and 'reply_to' not in msg.cw_edited:
rset = self._cw.find('Email', messageid=replyto)
......
change_relation_props('Email', 'sender', 'EmailAddress', commit=True, cardinality='?*')
# postcreate script. You could setup a workflow here for example
......@@ -6,10 +6,8 @@
"""
__docformat__ = "restructuredtext en"
try:
from cubicweb import _
except ImportError:
_ = unicode
from cubicweb import _
# pylint: disable-msg=E0611,F0401
from yams.buildobjs import (SubjectRelation, RelationType, EntityType,
......@@ -21,34 +19,34 @@ from cubicweb.schema import ERQLExpression
class Email(EntityType):
"""electronic mail"""
subject = String(fulltextindexed=True)
date = Datetime(description=_('UTC time on which the mail was sent'))
subject = String(fulltextindexed=True)
date = Datetime(description=_('UTC time on which the mail was sent'))
messageid = String(required=True, indexed=True, unique=True)
headers = String(description=_('raw headers'))
headers = String(description=_('raw headers'))
sender = SubjectRelation('EmailAddress', cardinality='?*')
sender = SubjectRelation('EmailAddress', cardinality='?*')
# an email with only Bcc is acceptable, don't require any recipients
recipients = SubjectRelation('EmailAddress')
cc = SubjectRelation('EmailAddress')
cc = SubjectRelation('EmailAddress')
parts = SubjectRelation('EmailPart', cardinality='*1', composite='subject')
attachment = SubjectRelation('File')
parts = SubjectRelation('EmailPart', cardinality='*1', composite='subject')
attachment = SubjectRelation('File')
reply_to = SubjectRelation('Email', cardinality='?*')
cites = SubjectRelation('Email')
in_thread = SubjectRelation('EmailThread', cardinality='?*')
reply_to = SubjectRelation('Email', cardinality='?*')
cites = SubjectRelation('Email')
in_thread = SubjectRelation('EmailThread', cardinality='?*')
class EmailPart(EntityType):
"""an email attachment"""
__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'),),
'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')),
'update': ('managers', 'owners',),
}
}
content = String(fulltextindexed=True)
content = String(fulltextindexed=True)
content_format = String(required=True, maxsize=50)
ordernum = Int(required=True)
alternative = SubjectRelation('EmailPart', symmetric=True)
......@@ -60,33 +58,37 @@ class EmailThread(EntityType):
see_also = SubjectRelation('EmailThread')
forked_from = SubjectRelation('EmailThread', cardinality='?*')
class parts(RelationType):
""" """
fulltext_container = 'subject'
class sender(RelationType):
""" """
inlined = True
class in_thread(RelationType):
""" """
inlined = True
class reply_to(RelationType):
""" """
inlined = True
class generated_by(RelationType):
"""mark an entity as generated from an email"""
cardinality = '?*'
subject = ('TrInfo',)
object = 'Email'
# if comment is installed
if 'Comment' in context.defined:
class comment_generated_by(RelationDefinition):
subject = 'Comment'
name = 'generated_by'
object = 'Email'
......@@ -37,5 +37,6 @@ class EmailValueGenerator(ValueGenerator):
This is required since the 'headers' attribute should be plain
ascii only
"""
def generate_Email_headers(self, entity, index):
return headers
Supports Markdown
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