Merge lp:~openerp-dev/openobject-addons/trunk-fetchmail-inbox-tde into lp:openobject-addons

Proposed by Thibault Delavallée (OpenERP)
Status: Superseded
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-fetchmail-inbox-tde
Merge into: lp:openobject-addons
Diff against target: 899 lines (+264/-149)
23 files modified
email_template/email_template.py (+2/-4)
fetchmail/fetchmail.py (+5/-5)
mail/data/mail_demo.xml (+10/-6)
mail/data/mail_group_data.xml (+3/-5)
mail/mail_followers.py (+15/-12)
mail/mail_message.py (+5/-2)
mail/mail_thread.py (+79/-32)
mail/res_partner.py (+18/-0)
mail/security/ir.model.access.csv (+4/-3)
mail/security/mail_security.xml (+9/-1)
mail/static/src/css/mail.css (+4/-0)
mail/static/src/js/mail.js (+1/-2)
mail/tests/__init__.py (+1/-0)
mail/tests/test_mail.py (+8/-40)
mail/tests/test_mail_access_rights.py (+2/-2)
mail/tests/test_mail_mockup.py (+54/-0)
mail/wizard/mail_compose_message_view.xml (+5/-5)
note/note.py (+1/-3)
pad/pad.py (+1/-1)
portal/mail_mail.py (+1/-1)
portal/portal_demo.xml (+33/-20)
portal/tests/test_portal.py (+2/-3)
portal/wizard/portal_wizard.py (+1/-2)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-fetchmail-inbox-tde
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+131936@code.launchpad.net

This proposal has been superseded by a proposal from 2012-11-14.

Commit message

Mail: improve incoming/outgoing emails behavior
Main:
- updated overall code to match the new mail openerp tools
- message_route: after checking the headers to find if the incoming email is a reply in an existing discussion, it checks whether the email is a reply to a private discussion (without model, res_id), based on the message_id of the mail; it then relies on the aliases then fetchmail, as before
- incoming emails and quick posting through Chatter now calls message_post_user_api (based on old message_post_api), that performs some things the composer do on its side (adding recipients of a replied message, cleaning the content)
Misc:
- mail: improved set_message_read, fixed a bug with message_id
- fetchmail: fixed a bug in fetchmail module about non-existing variable
- portal: updated demo data

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'email_template/email_template.py'
--- email_template/email_template.py 2012-11-07 11:39:25 +0000
+++ email_template/email_template.py 2012-11-14 09:23:22 +0000
@@ -28,8 +28,6 @@
28from osv import fields28from osv import fields
29import tools29import tools
30from tools.translate import _30from tools.translate import _
31from tools.html_sanitize import html_sanitize
32from tools import append_content_to_html
33from urllib import quote as quote31from urllib import quote as quote
34_logger = logging.getLogger(__name__)32_logger = logging.getLogger(__name__)
3533
@@ -293,10 +291,10 @@
293 or False291 or False
294 if template.user_signature:292 if template.user_signature:
295 signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature293 signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
296 values['body_html'] = append_content_to_html(values['body_html'], signature)294 values['body_html'] = tools.append_content_to_html(values['body_html'], signature)
297295
298 if values['body_html']:296 if values['body_html']:
299 values['body'] = html_sanitize(values['body_html'])297 values['body'] = tools.html_sanitize(values['body_html'])
300298
301 values.update(mail_server_id=template.mail_server_id.id or False,299 values.update(mail_server_id=template.mail_server_id.id or False,
302 auto_delete=template.auto_delete,300 auto_delete=template.auto_delete,
303301
=== modified file 'fetchmail/fetchmail.py'
--- fetchmail/fetchmail.py 2012-10-25 13:09:30 +0000
+++ fetchmail/fetchmail.py 2012-11-14 09:23:22 +0000
@@ -243,20 +243,20 @@
243243
244 def create(self, cr, uid, values, context=None):244 def create(self, cr, uid, values, context=None):
245 if context is None:245 if context is None:
246 context={}246 context = {}
247 fetchmail_server_id = context.get('fetchmail_server_id')247 fetchmail_server_id = context.get('fetchmail_server_id')
248 if fetchmail_server_id:248 if fetchmail_server_id:
249 values['fetchmail_server_id'] = fetchmail_server_id249 values['fetchmail_server_id'] = fetchmail_server_id
250 res = super(mail_mail,self).create(cr, uid, values, context=context)250 res = super(mail_mail, self).create(cr, uid, values, context=context)
251 return res251 return res
252252
253 def write(self, cr, uid, ids, values, context=None):253 def write(self, cr, uid, ids, values, context=None):
254 if context is None:254 if context is None:
255 context={}255 context = {}
256 fetchmail_server_id = context.get('fetchmail_server_id')256 fetchmail_server_id = context.get('fetchmail_server_id')
257 if fetchmail_server_id:257 if fetchmail_server_id:
258 values['fetchmail_server_id'] = server_id258 values['fetchmail_server_id'] = fetchmail_server_id
259 res = super(mail_mail,self).write(cr, uid, ids, values, context=context)259 res = super(mail_mail, self).write(cr, uid, ids, values, context=context)
260 return res260 return res
261261
262262
263263
=== modified file 'mail/data/mail_demo.xml'
--- mail/data/mail_demo.xml 2012-11-12 15:27:53 +0000
+++ mail/data/mail_demo.xml 2012-11-14 09:23:22 +0000
@@ -11,44 +11,48 @@
11 <record id="message_blogpost0" model="mail.message">11 <record id="message_blogpost0" model="mail.message">
12 <field name="model">mail.group</field>12 <field name="model">mail.group</field>
13 <field name="res_id" ref="mail.group_all_employees"/>13 <field name="res_id" ref="mail.group_all_employees"/>
14 <field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office.14 <field name="body"><![CDATA[<p>Your monthly meal vouchers arrived. You can get them at Christine's office.</p>]]></field>
15This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field>
16 <field name="type">comment</field>15 <field name="type">comment</field>
17 <field name="subtype_id" ref="mt_comment"/>16 <field name="subtype_id" ref="mt_comment"/>
17 <field name="author_id" ref="base.partner_root"/>
18 </record>18 </record>
19 <record id="message_blogpost0_comment0" model="mail.message">19 <record id="message_blogpost0_comment0" model="mail.message">
20 <field name="model">mail.group</field>20 <field name="model">mail.group</field>
21 <field name="res_id" ref="group_all_employees"/>21 <field name="res_id" ref="group_all_employees"/>
22 <field name="body"><![CDATA[Great.]]></field>22 <field name="body"><![CDATA[<p>Oh, I had forgotten. This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</p>]]></field>
23 <field name="parent_id" ref="message_blogpost0"/>23 <field name="parent_id" ref="message_blogpost0"/>
24 <field name="type">comment</field>24 <field name="type">comment</field>
25 <field name="subtype_id" ref="mt_comment"/>25 <field name="subtype_id" ref="mt_comment"/>
26 <field name="author_id" ref="base.partner_root"/>
26 </record>27 </record>
27 <record id="message_blogpost0_comment1" model="mail.message">28 <record id="message_blogpost0_comment1" model="mail.message">
28 <field name="model">mail.group</field>29 <field name="model">mail.group</field>
29 <field name="res_id" ref="group_all_employees"/>30 <field name="res_id" ref="group_all_employees"/>
30 <field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>31 <field name="body"><![CDATA[<p>Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!</p>]]></field>
31 <field name="parent_id" ref="message_blogpost0"/>32 <field name="parent_id" ref="message_blogpost0"/>
32 <field name="type">comment</field>33 <field name="type">comment</field>
33 <field name="subtype_id" ref="mt_comment"/>34 <field name="subtype_id" ref="mt_comment"/>
35 <field name="author_id" ref="base.partner_demo"/>
34 </record>36 </record>
35 <!-- This one is starred for having mailboxes with demo data -->37 <!-- This one is starred for having mailboxes with demo data -->
36 <record id="message_blogpost0_comment2" model="mail.message">38 <record id="message_blogpost0_comment2" model="mail.message">
37 <field name="model">mail.group</field>39 <field name="model">mail.group</field>
38 <field name="res_id" ref="group_all_employees"/>40 <field name="res_id" ref="group_all_employees"/>
39 <field name="body">Building B3, second floor on the right :-)</field>41 <field name="body"><![CDATA[<p>Building B3, second floor on the right :-).</p>]]></field>
40 <field name="parent_id" ref="message_blogpost0"/>42 <field name="parent_id" ref="message_blogpost0"/>
41 <field name="type">comment</field>43 <field name="type">comment</field>
42 <field name="subtype_id" ref="mt_comment"/>44 <field name="subtype_id" ref="mt_comment"/>
45 <field name="author_id" ref="base.partner_root"/>
43 <field name="favorite_user_ids" eval="[(6, 0, [ref('base.user_root'), ref('base.user_demo')])]"/>46 <field name="favorite_user_ids" eval="[(6, 0, [ref('base.user_root'), ref('base.user_demo')])]"/>
44 </record>47 </record>
45 <record id="message_blogpost0_comment3" model="mail.message">48 <record id="message_blogpost0_comment3" model="mail.message">
46 <field name="model">mail.group</field>49 <field name="model">mail.group</field>
47 <field name="res_id" ref="group_all_employees"/>50 <field name="res_id" ref="group_all_employees"/>
48 <field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field>51 <field name="body"><![CDATA[<p>Many thanks. Actually that's good news, next year I'll have to buy a new fridge, I think I will pay it with the eco-vouchers!</p>]]></field>
49 <field name="parent_id" ref="message_blogpost0"/>52 <field name="parent_id" ref="message_blogpost0"/>
50 <field name="type">comment</field>53 <field name="type">comment</field>
51 <field name="subtype_id" ref="mt_comment"/>54 <field name="subtype_id" ref="mt_comment"/>
55 <field name="author_id" ref="base.partner_demo"/>
52 </record>56 </record>
5357
54 <!-- Demo user and admin conversation -->58 <!-- Demo user and admin conversation -->
5559
=== modified file 'mail/data/mail_group_data.xml'
--- mail/data/mail_group_data.xml 2012-11-12 23:04:18 +0000
+++ mail/data/mail_group_data.xml 2012-11-14 09:23:22 +0000
@@ -18,11 +18,9 @@
18 <field name="res_id" ref="mail.group_all_employees"/>18 <field name="res_id" ref="mail.group_all_employees"/>
19 <field name="type">notification</field>19 <field name="type">notification</field>
20 <field name="subject">Welcome to OpenERP!</field>20 <field name="subject">Welcome to OpenERP!</field>
21 <field name="body">Your homepage is a summary of messages you received and key information about documents you follow.21 <field name="body"><![CDATA[<p>Your homepage is a summary of messages you received and key information about documents you follow.<br />
2222The top menu bar contains all applications you installed. You can use this &lt;i&gt;Settings&lt;/i&gt; menu to install more applications, activate others features or give access to new users.<br />
23The top menu bar contains all applications you installed. You can use this &lt;i&gt;Settings&lt;/i&gt; menu to install more applications, activate others features or give access to new users.23To setup your preferences (name, email signature, avatar), click on the top right corner.</p>]]></field>
24
25To setup your preferences (name, email signature, avatar), click on the top right corner.</field>
26 </record>24 </record>
27 </data>25 </data>
28</openerp>26</openerp>
2927
=== modified file 'mail/mail_followers.py'
--- mail/mail_followers.py 2012-11-12 13:17:59 +0000
+++ mail/mail_followers.py 2012-11-14 09:23:22 +0000
@@ -84,11 +84,13 @@
84 return False84 return False
8585
86 def set_message_read(self, cr, uid, msg_ids, read=None, context=None):86 def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
87 """ Set a message and its child messages as (un)read for uid.87 """ Set messages as (un)read. Technically, the notifications related
88 to uid are set to (un)read. If for some msg_ids there are missing
89 notifications (i.e. due to load more or thread parent fetching),
90 they are created.
8891
89 :param bool read: read / unread92 :param bool read: (un)read notification
90 """93 """
91 # TDE note: use child_of or front-end send correct values ?
92 user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]94 user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
93 notif_ids = self.search(cr, uid, [95 notif_ids = self.search(cr, uid, [
94 ('partner_id', '=', user_pid),96 ('partner_id', '=', user_pid),
@@ -100,10 +102,9 @@
100 return self.write(cr, uid, notif_ids, {'read': read}, context=context)102 return self.write(cr, uid, notif_ids, {'read': read}, context=context)
101103
102 # some messages do not have notifications: find which one, create notification, update read status104 # some messages do not have notifications: find which one, create notification, update read status
103 exist_notification = dict.fromkeys(msg_ids, False)105 notified_msg_ids = [notification.message_id.id for notification in self.browse(cr, uid, notif_ids, context=context)]
104 for notification in self.browse(cr, uid, notif_ids, context=context):106 to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
105 exist_notification[notification.message_id.id] = True107 for msg_id in to_create_msg_ids:
106 for msg_id in exist_notification.keys():
107 self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)108 self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)
108 return self.write(cr, uid, notif_ids, {'read': read}, context=context)109 return self.write(cr, uid, notif_ids, {'read': read}, context=context)
109110
@@ -150,16 +151,18 @@
150151
151 # add the context in the email152 # add the context in the email
152 # TDE FIXME: commented, to be improved in a future branch153 # TDE FIXME: commented, to be improved in a future branch
153 # quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)154 quote_context = self.pool.get('mail.message').message_quote_context(cr, uid, msg_id, context=context)
154155
155 mail_mail = self.pool.get('mail.mail')156 mail_mail = self.pool.get('mail.mail')
156 # add signature157 # add signature
157 body_html = msg.body158 body_html = msg.body
158 # if quote_context:159 if quote_context:
159 # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)160 pass
160 signature = msg.author_id and msg.author_id.user_ids[0].signature or ''161 # print quote_context
162 # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
163 signature = msg.author_id and msg.author_id.user_id and msg.author_id.user_ids[0].signature or ''
161 if signature:164 if signature:
162 body_html = tools.append_content_to_html(body_html, signature)165 body_html = tools.append_content_to_html(body_html, tools.text2html(signature), plaintext=False)
163166
164 mail_values = {167 mail_values = {
165 'mail_message_id': msg.id,168 'mail_message_id': msg.id,
166169
=== modified file 'mail/mail_message.py'
--- mail/mail_message.py 2012-11-12 14:04:08 +0000
+++ mail/mail_message.py 2012-11-14 09:23:22 +0000
@@ -25,6 +25,7 @@
25from email.header import decode_header25from email.header import decode_header
26from openerp import SUPERUSER_ID26from openerp import SUPERUSER_ID
27from openerp.osv import osv, orm, fields27from openerp.osv import osv, orm, fields
28from openerp.tools import html_email_clean
28from openerp.tools.translate import _29from openerp.tools.translate import _
2930
30_logger = logging.getLogger(__name__)31_logger = logging.getLogger(__name__)
@@ -280,7 +281,7 @@
280281
281 return {'id': message.id,282 return {'id': message.id,
282 'type': message.type,283 'type': message.type,
283 'body': message.body,284 'body': html_email_clean(message.body),
284 'model': message.model,285 'model': message.model,
285 'res_id': message.res_id,286 'res_id': message.res_id,
286 'record_name': message.record_name,287 'record_name': message.record_name,
@@ -633,6 +634,8 @@
633 def create(self, cr, uid, values, context=None):634 def create(self, cr, uid, values, context=None):
634 if not values.get('message_id') and values.get('res_id') and values.get('model'):635 if not values.get('message_id') and values.get('res_id') and values.get('model'):
635 values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)636 values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)
637 elif not values.get('message_id'):
638 values['message_id'] = tools.generate_tracking_message_id('private')
636 newid = super(mail_message, self).create(cr, uid, values, context)639 newid = super(mail_message, self).create(cr, uid, values, context)
637 self._notify(cr, SUPERUSER_ID, newid, context=context)640 self._notify(cr, SUPERUSER_ID, newid, context=context)
638 return newid641 return newid
@@ -763,7 +766,7 @@
763 ], context=context)766 ], context=context)
764 fol_objs = fol_obj.read(cr, uid, fol_ids, ['partner_id'], context=context)767 fol_objs = fol_obj.read(cr, uid, fol_ids, ['partner_id'], context=context)
765 partners_to_notify |= set(fol['partner_id'][0] for fol in fol_objs)768 partners_to_notify |= set(fol['partner_id'][0] for fol in fol_objs)
766 # when writing to a wall769 # remove me from notified partners, unless the message is written on my own wall
767 if message.get('author_id') and message.get('model') == "res.partner" and message.get('res_id') == message.get('author_id')[0]:770 if message.get('author_id') and message.get('model') == "res.partner" and message.get('res_id') == message.get('author_id')[0]:
768 partners_to_notify |= set([message.get('author_id')[0]])771 partners_to_notify |= set([message.get('author_id')[0]])
769 elif message.get('author_id'):772 elif message.get('author_id'):
770773
=== modified file 'mail/mail_thread.py'
--- mail/mail_thread.py 2012-11-12 13:10:51 +0000
+++ mail/mail_thread.py 2012-11-14 09:23:22 +0000
@@ -319,10 +319,12 @@
319 """319 """
320 assert isinstance(message, Message), 'message must be an email.message.Message at this point'320 assert isinstance(message, Message), 'message must be an email.message.Message at this point'
321 message_id = message.get('Message-Id')321 message_id = message.get('Message-Id')
322 references = decode_header(message, 'References')
323 in_reply_to = decode_header(message, 'In-Reply-To')
322324
323 # 1. Verify if this is a reply to an existing thread325 # 1. Verify if this is a reply to an existing thread
324 references = decode_header(message, 'References') or decode_header(message, 'In-Reply-To')326 thread_references = references or in_reply_to
325 ref_match = references and tools.reference_re.search(references)327 ref_match = thread_references and tools.reference_re.search(thread_references)
326 if ref_match:328 if ref_match:
327 thread_id = int(ref_match.group(1))329 thread_id = int(ref_match.group(1))
328 model = ref_match.group(2) or model330 model = ref_match.group(2) or model
@@ -333,6 +335,14 @@
333 message_id, model, thread_id, custom_values, uid)335 message_id, model, thread_id, custom_values, uid)
334 return [(model, thread_id, custom_values, uid)]336 return [(model, thread_id, custom_values, uid)]
335337
338 # Verify this is a reply to a private message
339 message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', in_reply_to)], limit=1, context=context)
340 if message_ids:
341 message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
342 _logger.debug('Routing mail with Message-Id %s: reply to a private message: %s, custom_values: %s, uid: %s',
343 message_id, message.id, custom_values, uid)
344 return [(False, 0, custom_values, uid)]
345
336 # 2. Look for a matching mail.alias entry346 # 2. Look for a matching mail.alias entry
337 # Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values347 # Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
338 # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.348 # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
@@ -376,14 +386,19 @@
376 def message_process(self, cr, uid, model, message, custom_values=None,386 def message_process(self, cr, uid, model, message, custom_values=None,
377 save_original=False, strip_attachments=False,387 save_original=False, strip_attachments=False,
378 thread_id=None, context=None):388 thread_id=None, context=None):
379 """Process an incoming RFC2822 email message, relying on389 """ Process an incoming RFC2822 email message, relying on
380 ``mail.message.parse()`` for the parsing operation,390 ``mail.message.parse()`` for the parsing operation,
381 and ``message_route()`` to figure out the target model.391 and ``message_route()`` to figure out the target model.
382392
383 Once the target model is known, its ``message_new`` method393 Once the target model is known, its ``message_new`` method
384 is called with the new message (if the thread record did not exist)394 is called with the new message (if the thread record did not exist)
385 or its ``message_update`` method (if it did).395 or its ``message_update`` method (if it did).
386396
397 There is a special case where the target model is False: a reply
398 to a private message. In this case, we skip the message_new /
399 message_update step, to just post a new message using mail_thread
400 message_post.
401
387 :param string model: the fallback model to use if the message402 :param string model: the fallback model to use if the message
388 does not match any of the currently configured mail aliases403 does not match any of the currently configured mail aliases
389 (may be None if a matching alias is supposed to be present)404 (may be None if a matching alias is supposed to be present)
@@ -425,15 +440,18 @@
425 for model, thread_id, custom_values, user_id in routes:440 for model, thread_id, custom_values, user_id in routes:
426 if self._name != model:441 if self._name != model:
427 context.update({'thread_model': model})442 context.update({'thread_model': model})
428 model_pool = self.pool.get(model)443 if model:
429 assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \444 model_pool = self.pool.get(model)
430 "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \445 assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
431 (msg['message_id'], model)446 "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
432 if thread_id and hasattr(model_pool, 'message_update'):447 (msg['message_id'], model)
433 model_pool.message_update(cr, user_id, [thread_id], msg, context=context)448 if thread_id and hasattr(model_pool, 'message_update'):
449 model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
450 else:
451 thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
434 else:452 else:
435 thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)453 model_pool = self.pool.get('mail.thread')
436 model_pool.message_post(cr, uid, [thread_id], context=context, **msg)454 model_pool.message_post_user_api(cr, uid, [thread_id], context=context, content_subtype='html', **msg)
437 return thread_id455 return thread_id
438456
439 def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):457 def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
@@ -556,7 +574,6 @@
556 """574 """
557 msg_dict = {575 msg_dict = {
558 'type': 'email',576 'type': 'email',
559 'subtype': 'mail.mt_comment',
560 'author_id': False,577 'author_id': False,
561 }578 }
562 if not isinstance(message, Message):579 if not isinstance(message, Message):
@@ -588,7 +605,7 @@
588 else:605 else:
589 msg_dict['email_from'] = message.get('from')606 msg_dict['email_from'] = message.get('from')
590 partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)607 partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)
591 msg_dict['partner_ids'] = partner_ids608 msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
592609
593 if 'Date' in message:610 if 'Date' in message:
594 date_hdr = decode(message.get('Date'))611 date_hdr = decode(message.get('Date'))
@@ -629,7 +646,8 @@
629 mail.message ID. Extra keyword arguments will be used as default646 mail.message ID. Extra keyword arguments will be used as default
630 column values for the new mail.message record.647 column values for the new mail.message record.
631 Auto link messages for same id and object648 Auto link messages for same id and object
632 :param int thread_id: thread ID to post into, or list with one ID649 :param int thread_id: thread ID to post into, or list with one ID;
650 if False/0, mail.message model will also be set as False
633 :param str body: body of the message, usually raw HTML that will651 :param str body: body of the message, usually raw HTML that will
634 be sanitized652 be sanitized
635 :param str subject: optional subject653 :param str subject: optional subject
@@ -639,10 +657,13 @@
639 ``(name,content)``, where content is NOT base64 encoded657 ``(name,content)``, where content is NOT base64 encoded
640 :return: ID of newly created mail.message658 :return: ID of newly created mail.message
641 """659 """
642 context = context or {}660 if context is None:
643 attachments = attachments or []661 context = {}
662 if attachments is None:
663 attachments = {}
664
644 assert (not thread_id) or isinstance(thread_id, (int, long)) or \665 assert (not thread_id) or isinstance(thread_id, (int, long)) or \
645 (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"666 (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id; should be 0, False, an ID or a list with one ID"
646 if isinstance(thread_id, (list, tuple)):667 if isinstance(thread_id, (list, tuple)):
647 thread_id = thread_id and thread_id[0]668 thread_id = thread_id and thread_id[0]
648 mail_message = self.pool.get('mail.message')669 mail_message = self.pool.get('mail.message')
@@ -682,7 +703,6 @@
682 # avoid loops when finding ancestors703 # avoid loops when finding ancestors
683 processed_list = []704 processed_list = []
684 if message_ids:705 if message_ids:
685 _counter, _counter_max = 0, 200
686 message = mail_message.browse(cr, SUPERUSER_ID, message_ids[0], context=context)706 message = mail_message.browse(cr, SUPERUSER_ID, message_ids[0], context=context)
687 while (message.parent_id and message.parent_id.id not in processed_list):707 while (message.parent_id and message.parent_id.id not in processed_list):
688 processed_list.append(message.parent_id.id)708 processed_list.append(message.parent_id.id)
@@ -707,18 +727,45 @@
707727
708 return mail_message.create(cr, uid, values, context=context)728 return mail_message.create(cr, uid, values, context=context)
709729
710 def message_post_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False, attachment_ids=None, context=None):730 def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
711 """ Wrapper on message_post, used only in Chatter (JS). The purpose is731 attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
712 to handle attachments.732 """ Wrapper on message_post, used for user input :
713 # TDE FIXME: body is plaintext: convert it into html733 - mail gateway
734 - quick reply in Chatter (refer to mail.js), not
735 the mail.compose.message wizard
736 The purpose is to perform some pre- and post-processing:
737 - if body is plaintext: convert it into html
738 - if parent_id: handle reply to a previous message by adding the
739 parent partners to the message
740 - type and subtype: comment and mail.mt_comment by default
741 - attachment_ids: supposed not attached to any document; attach them
742 to the related document. Should only be set by Chatter.
714 """743 """
715 new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type='comment',744 ir_attachment = self.pool.get('ir.attachment')
716 subtype='mail.mt_comment', parent_id=parent_id, context=context)745 mail_message = self.pool.get('mail.message')
717746
718 # HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message747 # 1. Pre-processing: body, partner_ids, type and subtype
748 if content_subtype == 'plaintext':
749 body = tools.text2html(body)
750
751 partner_ids = kwargs.pop('partner_ids', [])
752 if parent_id:
753 parent_message = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
754 partner_ids += [(4, partner.id) for partner in parent_message.partner_ids]
755 # TDE FIXME HACK: mail.thread -> private message
756 if self._name == 'mail.thread' and parent_message.author_id.id:
757 partner_ids.append((4, parent_message.author_id.id))
758
759 message_type = kwargs.pop('type', 'comment')
760 message_subtype = kwargs.pop('type', 'mail.mt_comment')
761
762 # 2. Post message
763 new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type,
764 subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs)
765
766 # 3. Post-processing
767 # HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
719 if attachment_ids:768 if attachment_ids:
720 ir_attachment = self.pool.get('ir.attachment')
721 mail_message = self.pool.get('mail.message')
722 filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [769 filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
723 ('res_model', '=', 'mail.compose.message'),770 ('res_model', '=', 'mail.compose.message'),
724 ('res_id', '=', 0),771 ('res_id', '=', 0),
725772
=== modified file 'mail/res_partner.py'
--- mail/res_partner.py 2012-10-15 13:23:13 +0000
+++ mail/res_partner.py 2012-11-14 09:23:22 +0000
@@ -42,4 +42,22 @@
42 'notification_email_send': lambda *args: 'comment'42 'notification_email_send': lambda *args: 'comment'
43 }43 }
4444
45 def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
46 subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
47 """ Override related to res.partner. In case of email message, set it as
48 private:
49 - add the target partner in the message partner_ids
50 - set thread_id as None, because this will trigger the 'private'
51 aspect of the message (model=False, res_id=False)
52 """
53 if isinstance(thread_id, (list, tuple)):
54 thread_id = thread_id[0]
55 if type == 'email':
56 partner_ids = kwargs.get('partner_ids', [])
57 if thread_id not in partner_ids:
58 partner_ids.append(thread_id)
59 kwargs['partner_ids'] = partner_ids
60 return super(res_partner_mail, self).message_post(cr, uid, False, body=body, subject=subject,
61 type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs)
62
45# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:63# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
4664
=== modified file 'mail/security/ir.model.access.csv'
--- mail/security/ir.model.access.csv 2012-11-06 15:04:31 +0000
+++ mail/security/ir.model.access.csv 2012-11-14 09:23:22 +0000
@@ -7,12 +7,13 @@
7access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,07access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,0
8access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,18access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1
9access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,09access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0
10access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,110access_mail_notification_group_user,mail.notification.user,model_mail_notification,base.group_user,1,1,1,0
11access_mail_notification_system,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
11access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,012access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
12access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,113access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
13access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,014access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
14access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,015access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,0
15access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,116access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1
16access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,017access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0
17access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,118access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
18access_mail_favorite_all,mail.favorite.all,model_mail_favorite,,1,1,1,119access_mail_favorite_all,mail.favorite.all,model_mail_favorite,,1,1,1,1
1920
=== modified file 'mail/security/mail_security.xml'
--- mail/security/mail_security.xml 2012-10-19 09:59:19 +0000
+++ mail/security/mail_security.xml 2012-11-14 09:23:22 +0000
@@ -10,7 +10,7 @@
10 <field name="domain_force">['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&amp;', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])]</field>10 <field name="domain_force">['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&amp;', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])]</field>
11 </record>11 </record>
1212
13 <record id="mail_followers_read_own" model="ir.rule">13 <record id="mail_followers_read_write_own" model="ir.rule">
14 <field name="name">mail.followers: read and write its own entries</field>14 <field name="name">mail.followers: read and write its own entries</field>
15 <field name="model_id" ref="model_mail_followers"/>15 <field name="model_id" ref="model_mail_followers"/>
16 <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>16 <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
@@ -18,6 +18,14 @@
18 <field name="perm_unlink" eval="False"/>18 <field name="perm_unlink" eval="False"/>
19 </record>19 </record>
2020
21 <record id="mail_notification_read_write_own" model="ir.rule">
22 <field name="name">mail.notification: read and write its own entries</field>
23 <field name="model_id" ref="model_mail_notification"/>
24 <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
25 <field name="perm_create" eval="False"/>
26 <field name="perm_unlink" eval="False"/>
27 </record>
28
21 <!--29 <!--
22 This rule can not be uncommented, because we have a more wide method in mail.message. When we implement a many2one_variable field, we will be able to uncomment this.30 This rule can not be uncommented, because we have a more wide method in mail.message. When we implement a many2one_variable field, we will be able to uncomment this.
23 <record id="mail_message_read_partner_or_author" model="ir.rule">31 <record id="mail_message_read_partner_or_author" model="ir.rule">
2432
=== modified file 'mail/static/src/css/mail.css'
--- mail/static/src/css/mail.css 2012-11-13 10:35:30 +0000
+++ mail/static/src/css/mail.css 2012-11-14 09:23:22 +0000
@@ -87,6 +87,10 @@
87 margin-bottom: 0px;87 margin-bottom: 0px;
88 margin-top: 2px;88 margin-top: 2px;
89}89}
90.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p{
91 margin-top: 2px;
92 margin-bottom: 2px;
93}
9094
91/* a) Indented Messages */95/* a) Indented Messages */
9296
9397
=== modified file 'mail/static/src/js/mail.js'
--- mail/static/src/js/mail.js 2012-11-13 14:57:22 +0000
+++ mail/static/src/js/mail.js 2012-11-14 09:23:22 +0000
@@ -590,7 +590,7 @@
590590
591 if (body.match(/\S+/)) {591 if (body.match(/\S+/)) {
592 //session.web.blockUI();592 //session.web.blockUI();
593 this.parent_thread.ds_thread.call('message_post_api', [593 this.parent_thread.ds_thread.call('message_post_user_api', [
594 this.context.default_res_id, 594 this.context.default_res_id,
595 mail.ChatterUtils.get_text2html(body), 595 mail.ChatterUtils.get_text2html(body),
596 false, 596 false,
@@ -728,7 +728,6 @@
728728
729 mail.ThreadMessage = mail.MessageCommon.extend({729 mail.ThreadMessage = mail.MessageCommon.extend({
730 template: 'mail.thread.message',730 template: 'mail.thread.message',
731
732 731
733 start: function () {732 start: function () {
734 this._super.apply(this, arguments);733 this._super.apply(this, arguments);
735734
=== modified file 'mail/tests/__init__.py'
--- mail/tests/__init__.py 2012-09-14 11:58:15 +0000
+++ mail/tests/__init__.py 2012-11-14 09:23:22 +0000
@@ -18,6 +18,7 @@
18# along with this program. If not, see <http://www.gnu.org/licenses/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#19#
20##############################################################################20##############################################################################
21
21from . import test_mail, test_mail_access_rights22from . import test_mail, test_mail_access_rights
2223
23checks = [24checks = [
2425
=== modified file 'mail/tests/test_mail.py'
--- mail/tests/test_mail.py 2012-11-09 15:11:22 +0000
+++ mail/tests/test_mail.py 2012-11-14 09:23:22 +0000
@@ -21,8 +21,8 @@
2121
22import tools22import tools
2323
24from openerp.tests import common24from openerp.addons.mail.tests import test_mail_mockup
25from openerp.tools.html_sanitize import html_sanitize25from openerp.tools.mail import html_sanitize
2626
27MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>27MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
28To: {to}28To: {to}
@@ -84,43 +84,11 @@
84"""84"""
8585
8686
87class TestMailMockups(common.TransactionCase):87class test_mail(test_mail_mockup.TestMailMockups):
88
89 def _mock_smtp_gateway(self, *args, **kwargs):
90 return True
91
92 def _init_mock_build_email(self):
93 self._build_email_args_list = []
94 self._build_email_kwargs_list = []
95
96 def _mock_build_email(self, *args, **kwargs):
97 """ Mock build_email to be able to test its values. Store them into
98 some internal variable for latter processing. """
99 self._build_email_args_list.append(args)
100 self._build_email_kwargs_list.append(kwargs)
101 return self._build_email(*args, **kwargs)
102
103 def setUp(self):
104 super(TestMailMockups, self).setUp()
105 # Install mock SMTP gateway
106 self._init_mock_build_email()
107 self._build_email = self.registry('ir.mail_server').build_email
108 self.registry('ir.mail_server').build_email = self._mock_build_email
109 self._send_email = self.registry('ir.mail_server').send_email
110 self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
111
112 def tearDown(self):
113 # Remove mocks
114 self.registry('ir.mail_server').build_email = self._build_email
115 self.registry('ir.mail_server').send_email = self._send_email
116 super(TestMailMockups, self).tearDown()
117
118
119class test_mail(TestMailMockups):
12088
121 def _mock_send_get_mail_body(self, *args, **kwargs):89 def _mock_send_get_mail_body(self, *args, **kwargs):
122 # def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)90 # def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
123 body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner')91 body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner', plaintext=False)
124 return body92 return body
12593
126 def setUp(self):94 def setUp(self):
@@ -375,10 +343,10 @@
375 _subject = 'Pigs'343 _subject = 'Pigs'
376 _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)344 _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
377 _body1 = 'Pigs rules'345 _body1 = 'Pigs rules'
378 _mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'346 _mail_body1 = 'Pigs rules\n<div><p>Admin</p></div>\n'
379 _mail_bodyalt1 = 'Pigs rules\nAdmin'347 _mail_bodyalt1 = 'Pigs rules\nAdmin\n'
380 _body2 = '<html>Pigs rules</html>'348 _body2 = '<html>Pigs rules</html>'
381 _mail_body2 = html_sanitize('<html>Pigs rules\n<pre>Admin</pre>\n</html>')349 _mail_body2 = html_sanitize('<html>Pigs rules\n<div><p>Admin</p></div>\n</html>')
382 _mail_bodyalt2 = 'Pigs rules\nAdmin'350 _mail_bodyalt2 = 'Pigs rules\nAdmin'
383 _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]351 _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
384352
@@ -399,7 +367,7 @@
399 # Test: sent_email: email send by server: correct subject, body, body_alternative367 # Test: sent_email: email send by server: correct subject, body, body_alternative
400 for sent_email in sent_emails:368 for sent_email in sent_emails:
401 self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')369 self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
402 self.assertEqual(sent_email['body'], _mail_body1 + '\n<pre>Bert Tartopoils</pre>\n', 'sent_email body incorrect')370 self.assertEqual(sent_email['body'], _mail_body1 + '\nBert Tartopoils\n', 'sent_email body incorrect')
403 # the html2plaintext uses etree or beautiful soup, so the result may be slighly different371 # the html2plaintext uses etree or beautiful soup, so the result may be slighly different
404 # depending if you have installed beautiful soup.372 # depending if you have installed beautiful soup.
405 self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')373 self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
406374
=== modified file 'mail/tests/test_mail_access_rights.py'
--- mail/tests/test_mail_access_rights.py 2012-10-25 11:30:48 +0000
+++ mail/tests/test_mail_access_rights.py 2012-11-14 09:23:22 +0000
@@ -19,11 +19,11 @@
19#19#
20##############################################################################20##############################################################################
2121
22from openerp.addons.mail.tests import test_mail22from openerp.addons.mail.tests import test_mail_mockup
23from osv.orm import except_orm23from osv.orm import except_orm
2424
2525
26class test_mail_access_rights(test_mail.TestMailMockups):26class test_mail_access_rights(test_mail_mockup.TestMailMockups):
2727
28 def setUp(self):28 def setUp(self):
29 super(test_mail_access_rights, self).setUp()29 super(test_mail_access_rights, self).setUp()
3030
=== added file 'mail/tests/test_mail_mockup.py'
--- mail/tests/test_mail_mockup.py 1970-01-01 00:00:00 +0000
+++ mail/tests/test_mail_mockup.py 2012-11-14 09:23:22 +0000
@@ -0,0 +1,54 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Business Applications
5# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from openerp.tests import common
23
24
25class TestMailMockups(common.TransactionCase):
26
27 def _mock_smtp_gateway(self, *args, **kwargs):
28 return True
29
30 def _init_mock_build_email(self):
31 self._build_email_args_list = []
32 self._build_email_kwargs_list = []
33
34 def _mock_build_email(self, *args, **kwargs):
35 """ Mock build_email to be able to test its values. Store them into
36 some internal variable for latter processing. """
37 self._build_email_args_list.append(args)
38 self._build_email_kwargs_list.append(kwargs)
39 return self._build_email(*args, **kwargs)
40
41 def setUp(self):
42 super(TestMailMockups, self).setUp()
43 # Install mock SMTP gateway
44 self._init_mock_build_email()
45 self._build_email = self.registry('ir.mail_server').build_email
46 self.registry('ir.mail_server').build_email = self._mock_build_email
47 self._send_email = self.registry('ir.mail_server').send_email
48 self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
49
50 def tearDown(self):
51 # Remove mocks
52 self.registry('ir.mail_server').build_email = self._build_email
53 self.registry('ir.mail_server').send_email = self._send_email
54 super(TestMailMockups, self).tearDown()
055
=== modified file 'mail/wizard/mail_compose_message_view.xml'
--- mail/wizard/mail_compose_message_view.xml 2012-11-13 08:41:53 +0000
+++ mail/wizard/mail_compose_message_view.xml 2012-11-14 09:23:22 +0000
@@ -8,11 +8,11 @@
8 <form string="Compose Email" version="7.0">8 <form string="Compose Email" version="7.0">
9 <group>9 <group>
10 <!-- truly invisible fields for control and options -->10 <!-- truly invisible fields for control and options -->
11 <field name="composition_mode" invisible="1"/>11 <field name="composition_mode" invisible="0"/>
12 <field name="model" invisible="1"/>12 <field name="model" invisible="0"/>
13 <field name="res_id" invisible="1"/>13 <field name="res_id" invisible="0"/>
14 <field name="parent_id" invisible="1"/>14 <field name="parent_id" invisible="0"/>
15 <field name="content_subtype" invisible="1"/>15 <field name="content_subtype" invisible="0"/>
16 <!-- visible wizard -->16 <!-- visible wizard -->
17 <label for="partner_ids" string="Recipients"/>17 <label for="partner_ids" string="Recipients"/>
18 <div>18 <div>
1919
=== modified file 'note/note.py'
--- note/note.py 2012-11-02 13:17:59 +0000
+++ note/note.py 2012-11-14 09:23:22 +0000
@@ -20,9 +20,7 @@
20##############################################################################20##############################################################################
2121
22from openerp.osv import osv, fields22from openerp.osv import osv, fields
23from tools.translate import _23from openerp.tools import html2plaintext
24import re
25from openerp.tools.misc import html2plaintext
2624
27class note_stage(osv.osv):25class note_stage(osv.osv):
28 """ Category of Note """26 """ Category of Note """
2927
=== modified file 'pad/pad.py'
--- pad/pad.py 2012-11-09 06:30:02 +0000
+++ pad/pad.py 2012-11-14 09:23:22 +0000
@@ -6,7 +6,7 @@
6import urllib26import urllib2
7import logging7import logging
8from tools.translate import _8from tools.translate import _
9from openerp.tools.misc import html2plaintext9from openerp.tools import html2plaintext
10from py_etherpad import EtherpadLiteClient10from py_etherpad import EtherpadLiteClient
1111
12_logger = logging.getLogger(__name__)12_logger = logging.getLogger(__name__)
1313
=== modified file 'portal/mail_mail.py'
--- portal/mail_mail.py 2012-10-01 09:14:41 +0000
+++ portal/mail_mail.py 2012-11-14 09:23:22 +0000
@@ -36,5 +36,5 @@
36 if partner:36 if partner:
37 context = dict(context or {}, signup_valid=True)37 context = dict(context or {}, signup_valid=True)
38 partner = self.pool.get('res.partner').browse(cr, uid, partner.id, context)38 partner = self.pool.get('res.partner').browse(cr, uid, partner.id, context)
39 body = tools.append_content_to_html(body, "Log in our portal at: %s" % partner.signup_url)39 body = tools.append_content_to_html(body, ("<div><p>Log in our portal at: %s</p></div>" % partner.signup_url), plaintext=False)
40 return body40 return body
4141
=== modified file 'portal/portal_demo.xml'
--- portal/portal_demo.xml 2012-09-20 14:57:53 +0000
+++ portal/portal_demo.xml 2012-11-14 09:23:22 +0000
@@ -1,22 +1,27 @@
1<?xml version="1.0"?>1<?xml version="1.0"?>
2<openerp>2<openerp>
3 <data>3 <data noupdate="1">
44
5 <!-- Create a portal member attached to a partner -->5 <!-- Create a partner, that is also a portal user -->
6 <record id="demo_user0" model="res.users">6 <record id="partner_demo_portal" model="res.partner">
7 <field name="name">Demo Portal User</field>7 <field name="name">Demo Portal User</field>
8 <field name="email">demo@portal.example.com</field>
9 <field name="supplier" eval="False"/>
10 <field name="customer" eval="True"/>
11 </record>
12 <record id="user_demo_portal" model="res.users">
13 <field name="partner_id" ref="partner_demo_portal"/>
8 <field name="login">portal</field>14 <field name="login">portal</field>
9 <field name="password">portal</field>15 <field name="password">portal</field>
16 <field name="signature">--
17Mr Demo Portal</field>
10 <!-- Avoid auto-including this user in any default group -->18 <!-- Avoid auto-including this user in any default group -->
11 <field name="groups_id" eval="[(5,)]"/>19 <field name="groups_id" eval="[(5,)]"/>
12 <field name="supplier" eval="False"/>
13 <field name="customer" eval="True"/>
14 <field name="email">demo@portal.wrong.address</field>
15 </record>20 </record>
1621
17 <!-- Add the demo user to the portal (and therefore to the portal member group) -->22 <!-- Add the demo user to the portal (and therefore to the portal member group) -->
18 <record id="group_portal" model="res.groups">23 <record id="group_portal" model="res.groups">
19 <field name="users" eval="[(4,ref('demo_user0'))]"/>24 <field name="users" eval="[(4,ref('user_demo_portal'))]"/>
20 </record>25 </record>
2126
22 <!-- Company news and comments -->27 <!-- Company news and comments -->
@@ -24,33 +29,41 @@
24 <field name="subject">Our company's first blog-post !</field>29 <field name="subject">Our company's first blog-post !</field>
25 <field name="model">mail.group</field>30 <field name="model">mail.group</field>
26 <field name="res_id" ref="company_news_feed"/>31 <field name="res_id" ref="company_news_feed"/>
27 <field name="body"><![CDATA[Hello, and welcome to our company's portal !32 <field name="body"><![CDATA[<p>Hello, and welcome to our company's portal !</p>
2833<p>It is a great pleasure to announce you the creation of our portal by writing this first news! As you may have seen, a new discussion group is now present under your 'My groups' menu: <b>Company's News</b>. We will post news about the company and its employees in this discussion group. Moreover, we will be able to communicate with our partners that are given the opportunity to join us in our portal.</p>
29Lorem ipsum <b>sit amet</b>, consectetur <em>adipiscing elit</em>. Pellentesque et quam sapien, in sagittis tellus.34<p>A new era of communication has begun! <b>Feel free to post your feelings about our portal by replying on this message!</b></p>]]></field>
30Praesent vel massa sed massa consequat egestas in tristique orci. Praesent iaculis libero et neque vehicula iaculis. Vivamus placerat tincidunt orci ac ornare. Proin ut dolor fringilla velit ultricies consequat. Maecenas sit amet ipsum non leo interdum imperdiet. Donec sapien mi.
31
32Fusce tempus elit volutpat mi auctor adipiscing. Nam congue luctus suscipit. Sed tellus libero, venenatis ut mollis ut, luctus quis dui. Sed rhoncus pulvinar orci in consectetur.
33
34Nulla turpis leo, rhoncus ut egestas sit amet, consectetur vitae urna. Mauris in dolor in sapien tempus vehicula.]]></field>
35 <field name="type">comment</field>35 <field name="type">comment</field>
36 <field name="subtype_id" ref="mail.mt_comment"/>
36 <field name="author_id" ref="base.partner_root"/>37 <field name="author_id" ref="base.partner_root"/>
37 </record>38 </record>
3839
39 <record id="message_company_news0_comment0" model="mail.message">40 <record id="message_company_news0_comment0" model="mail.message">
40 <field name="model">mail.group</field>41 <field name="model">mail.group</field>
41 <field name="res_id" ref="company_news_feed"/>42 <field name="res_id" ref="company_news_feed"/>
42 <field name="body"><![CDATA[Great first blogpost ! (first comment)]]></field>43 <field name="body"><![CDATA[<p>As your first portal member, I am very pleased to be able to be able to communicate directly with you. Be sure I'll read all news carefully!</p>]]></field>
43 <field name="parent_id" ref="message_company_news0"/>44 <field name="parent_id" ref="message_company_news0"/>
44 <field name="type">comment</field>45 <field name="type">comment</field>
46 <field name="subtype_id" ref="mail.mt_comment"/>
47 <field name="author_id" ref="partner_demo_portal"/>
48 </record>
49
50 <record id="message_company_news0_comment1" model="mail.message">
51 <field name="model">mail.group</field>
52 <field name="res_id" ref="company_news_feed"/>
53 <field name="body"><![CDATA[<p>That's good news! As said by <i>Demo Portal User</i> in the previous post, I'm looking forward to hearing from you!</p>]]></field>
54 <field name="parent_id" ref="message_company_news0"/>
55 <field name="type">comment</field>
56 <field name="subtype_id" ref="mail.mt_comment"/>
45 <field name="author_id" ref="base.res_partner_1"/>57 <field name="author_id" ref="base.res_partner_1"/>
46 </record>58 </record>
4759
48 <record id="message_company_news0_comment1" model="mail.message">60 <record id="message_company_news0_comment2" model="mail.message">
49 <field name="model">mail.group</field>61 <field name="model">mail.group</field>
50 <field name="res_id" ref="company_news_feed"/>62 <field name="res_id" ref="company_news_feed"/>
51 <field name="body"><![CDATA[Thanks ! (second comment)]]></field>63 <field name="body"><![CDATA[<p>This feature is realy great! We will be able to communicate directly to our partners!</p>]]></field>
52 <field name="parent_id" ref="message_company_news0"/>64 <field name="parent_id" ref="message_company_news0"/>
53 <field name="type">comment</field>65 <field name="type">comment</field>
66 <field name="subtype_id" ref="mail.mt_comment"/>
54 <field name="author_id" ref="base.partner_demo"/>67 <field name="author_id" ref="base.partner_demo"/>
55 </record>68 </record>
5669
5770
=== modified file 'portal/tests/test_portal.py'
--- portal/tests/test_portal.py 2012-10-09 15:54:56 +0000
+++ portal/tests/test_portal.py 2012-11-14 09:23:22 +0000
@@ -19,12 +19,11 @@
19#19#
20##############################################################################20##############################################################################
2121
22from openerp.addons.mail.tests import test_mail22from openerp.addons.mail.tests import test_mail_mockup
23from openerp.tools import append_content_to_html
24from osv.orm import except_orm23from osv.orm import except_orm
2524
2625
27class test_portal(test_mail.TestMailMockups):26class test_portal(test_mail_mockup.TestMailMockups):
2827
29 def setUp(self):28 def setUp(self):
30 super(test_portal, self).setUp()29 super(test_portal, self).setUp()
3130
=== modified file 'portal/wizard/portal_wizard.py'
--- portal/wizard/portal_wizard.py 2012-10-25 13:09:30 +0000
+++ portal/wizard/portal_wizard.py 2012-11-14 09:23:22 +0000
@@ -24,10 +24,9 @@
2424
25from osv import osv, fields25from osv import osv, fields
26from tools.translate import _26from tools.translate import _
27from tools.misc import email_re27from tools import email_re
28from openerp import SUPERUSER_ID28from openerp import SUPERUSER_ID
2929
30from base.res.res_partner import _lang_get
31_logger = logging.getLogger(__name__)30_logger = logging.getLogger(__name__)
3231
33# welcome email sent to portal users32# welcome email sent to portal users

Subscribers

People subscribed via source and target branches

to all changes: