Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
cubicweb
cubes
email
Commits
89987290b133
Commit
a9deecc9
authored
Feb 15, 2010
by
Sylvain Thénault
Browse files
default is now stable
--HG-- branch : stable
parents
cf4d3a6106ed
788622aba4ba
Changes
11
Hide whitespace changes
Inline
Side-by-side
.hgtags
View file @
89987290
...
...
@@ -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
__pkginfo__.py
View file @
89987290
...
...
@@ -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-200
9
LOGILAB S.A. (Paris, FRANCE).
copyright
=
'''Copyright (c) 2003-20
1
0 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'
,)
...
...
e
cplugin.py
→
c
cplugin.py
View file @
89987290
File moved
debian/changelog
View file @
89987290
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
...
...
debian/control
View file @
89987290
...
...
@@ -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.
.
...
...
entities.py
View file @
89987290
...
...
@@ -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
):
...
...
hooks.py
View file @
89987290
...
...
@@ -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.se
rver.hooksmanager
import
Hook
from
cubicweb.
common.mail
import
parse_message_id
from
cubicweb.
mail
import
parse_message_id
from
cubicweb.se
lectors
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
(
PreCommit
Operation
):
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
.
s
chema
.
r
schema
(
'comments'
)
.
objects
(
'Comment'
):
return
if
origetype
in
self
.
s
ession
.
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
(
PreCommit
Operation
):
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
se
ssion
.
repo
.
schema
:
for
msgid
in
entity
.
references
():
info
=
parse_message_id
(
msgid
,
self
.
config
.
appid
)
def
__
call
__
(
self
):
if
'comments'
in
se
lf
.
_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
(
se
ssion
,
email
=
entity
,
info
=
info
)
ExtractEmailInformation
(
se
lf
.
_cw
,
email
=
self
.
entity
,
info
=
info
)
break
AnalyzeEmailText
(
se
ssion
,
email
=
entity
)
AnalyzeEmailText
(
se
lf
.
_cw
,
email
=
self
.
entity
)
schema.py
View file @
89987290
...
...
@@ -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'
,
sym
m
etric
=
True
)
class
EmailThread
(
EntityType
):
...
...
test/unittest_hooks.py
View file @
89987290
...
...
@@ -4,7 +4,7 @@ from StringIO import StringIO
from
logilab.common.testlib
import
unittest_main
from
cubicweb.devtools.
app
test
import
EnvBased
TC
from
cubicweb.devtools.test
lib
import
CubicWeb
TC
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
(
EnvBased
TC
):
class
ChangeStateHooksTC
(
CubicWeb
TC
):
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
(
EnvBased
TC
):
class
ReplyCommentHooksTC
(
CubicWeb
TC
):
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
))
...
...
test/unittest_mboximport.py
View file @
89987290
...
...
@@ -4,15 +4,15 @@ from StringIO import StringIO
from
logilab.common.testlib
import
TestCase
,
unittest_main
from
cubicweb.devtools.
app
test
import
EnvBased
TC
from
cubicweb.devtools.test
lib
import
CubicWeb
TC
from
cubes.email.mboximport
import
MBOXImporter
class
MBOXImporterTC
(
EnvBased
TC
):
class
MBOXImporterTC
(
CubicWeb
TC
):
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
)
...
...
views/email.py
View file @
89987290
...
...
@@ -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 %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> %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> %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'
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment