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

Proposed by Thibault Delavallée (OpenERP)
Status: Merged
Merged at revision: 8037
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-fetchmail-inbox-tde
Merge into: lp:openobject-addons
Diff against target: 1220 lines (+316/-199)
40 files modified
account_accountant/account_accountant_data.xml (+3/-5)
account_voucher/account_voucher_data.xml (+3/-5)
crm/crm_data.xml (+3/-2)
email_template/email_template.py (+2/-4)
email_template/tests/test_mail.py (+6/-6)
fetchmail/fetchmail.py (+5/-5)
hr/hr_data.xml (+4/-4)
hr_evaluation/hr_evaluation_data.xml (+2/-2)
hr_expense/hr_expense_data.xml (+3/-3)
hr_holidays/hr_holidays_data.xml (+3/-2)
hr_recruitment/hr_recruitment_data.xml (+3/-3)
hr_timesheet_sheet/hr_timesheet_sheet_data.xml (+2/-1)
mail/data/mail_demo.xml (+10/-6)
mail/data/mail_group_data.xml (+4/-5)
mail/mail_followers.py (+11/-10)
mail/mail_message.py (+5/-2)
mail/mail_thread.py (+82/-34)
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)
mrp/mrp_data.xml (+4/-4)
note/note.py (+1/-3)
pad/pad.py (+1/-1)
point_of_sale/point_of_sale_data.xml (+3/-3)
portal/mail_mail.py (+1/-1)
portal/portal_demo.xml (+32/-19)
portal/tests/test_portal.py (+2/-3)
portal/wizard/portal_wizard.py (+1/-2)
project/project_data.xml (+4/-4)
project_gtd/project_gtd_data.xml (+3/-2)
project_issue/project_issue_data.xml (+3/-2)
purchase/purchase_data.xml (+3/-3)
sale/sale_data.xml (+3/-3)
stock/stock_data.xml (+3/-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+134269@code.launchpad.net

This proposal supersedes a proposal from 2012-10-29.

Description of the change

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:
- general: updated modules according to the new tools mail functions
- general: message related to a new app installation now have a comment subtype, meaning they will effectively be pushed
- 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
1=== modified file 'account_accountant/account_accountant_data.xml'
2--- account_accountant/account_accountant_data.xml 2012-10-16 11:23:23 +0000
3+++ account_accountant/account_accountant_data.xml 2012-11-14 14:39:22 +0000
4@@ -26,12 +26,10 @@
5 <field name="model">mail.group</field>
6 <field name="res_id" ref="mail.group_all_employees"/>
7 <field name="type">notification</field>
8+ <field name="subtype_id" ref="mail.mt_comment"/>
9 <field name="subject">Accounting and Finance application installed!</field>
10- <field name="body"><![CDATA[
11- With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.
12-
13-<p>The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</p>
14- ]]></field>
15+ <field name="body"><![CDATA[<p>With OpenERP's accounting, you get instant access to your financial data, and can setup analytic accounting, forecast taxes, control budgets, easily create and send invoices, record bank statements, etc.</p>
16+<p>The accounting features are fully integrated with other OpenERP applications to automate all your processes: creation of customer invoices, control of supplier invoices, point-of-sale integration, automated follow-ups, etc.</p>]]></field>
17 </record>
18 </data>
19 </openerp>
20
21=== modified file 'account_voucher/account_voucher_data.xml'
22--- account_voucher/account_voucher_data.xml 2012-10-02 20:40:23 +0000
23+++ account_voucher/account_voucher_data.xml 2012-11-14 14:39:22 +0000
24@@ -7,12 +7,10 @@
25 <field name="model">mail.group</field>
26 <field name="res_id" ref="mail.group_all_employees"/>
27 <field name="type">notification</field>
28+ <field name="subtype_id" ref="mail.mt_comment"/>
29 <field name="subject">eInvoicing &amp; Payments application installed!</field>
30- <field name="body"><![CDATA[
31- OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.
32-
33-<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>
34- ]]></field>
35+ <field name="body"><![CDATA[<p>OpenERP's electronic invoicing accelerates the creation of invoices and collection of customer payments. Invoices are created in a few clicks and your customers receive them by email. They can pay online and/or import them in their own system.</p>
36+<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>]]></field>
37 </record>
38
39 <!-- mail: subtypes -->
40
41=== modified file 'crm/crm_data.xml'
42--- crm/crm_data.xml 2012-09-17 06:57:40 +0000
43+++ crm/crm_data.xml 2012-11-14 14:39:22 +0000
44@@ -58,9 +58,10 @@
45 <field name="model">mail.group</field>
46 <field name="res_id" ref="mail.group_all_employees"/>
47 <field name="type">notification</field>
48+ <field name="subtype_id" ref="mail.mt_comment"/>
49 <field name="subject">CRM application installed!</field>
50- <field name="body">From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.
51-To manage quotations and sale orders, install the "Sales Management" application.</field>
52+ <field name="body"><![CDATA[<p>From the top Sales menu you can track leads and opportunities, get accurate forecast on your sales pipeline, plan meetings and phonecalls, get realtime statistics and efficiently organize the communication with your prospects.</p>
53+<br />To manage quotations and sale orders, install the "Sales Management" application.</p>]]></field>
54 </record>
55
56 <record model="mail.alias" id="default_sales_alias">
57
58=== modified file 'email_template/email_template.py'
59--- email_template/email_template.py 2012-11-07 11:39:25 +0000
60+++ email_template/email_template.py 2012-11-14 14:39:22 +0000
61@@ -28,8 +28,6 @@
62 from osv import fields
63 import tools
64 from tools.translate import _
65-from tools.html_sanitize import html_sanitize
66-from tools import append_content_to_html
67 from urllib import quote as quote
68 _logger = logging.getLogger(__name__)
69
70@@ -293,10 +291,10 @@
71 or False
72 if template.user_signature:
73 signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
74- values['body_html'] = append_content_to_html(values['body_html'], signature)
75+ values['body_html'] = tools.append_content_to_html(values['body_html'], signature)
76
77 if values['body_html']:
78- values['body'] = html_sanitize(values['body_html'])
79+ values['body'] = tools.html_sanitize(values['body_html'])
80
81 values.update(mail_server_id=template.mail_server_id.id or False,
82 auto_delete=template.auto_delete,
83
84=== modified file 'email_template/tests/test_mail.py'
85--- email_template/tests/test_mail.py 2012-11-13 13:10:44 +0000
86+++ email_template/tests/test_mail.py 2012-11-14 14:39:22 +0000
87@@ -20,10 +20,10 @@
88 ##############################################################################
89
90 import base64
91-from openerp.addons.mail.tests import test_mail
92-
93-
94-class test_message_compose(test_mail.TestMailMockups):
95+from openerp.addons.mail.tests import test_mail_mockup
96+
97+
98+class test_message_compose(test_mail_mockup.TestMailMockups):
99
100 def setUp(self):
101 super(test_message_compose, self).setUp()
102@@ -52,8 +52,8 @@
103 # Mail data
104 _subject1 = 'Pigs'
105 _subject2 = 'Bird'
106- _body_html1 = 'Fans of Pigs, unite !\n<pre>Admin</pre>\n'
107- _body_html2 = 'I am angry !\n<pre>Admin</pre>\n'
108+ _body_html1 = 'Fans of Pigs, unite !\n<p>Admin</p>\n'
109+ _body_html2 = 'I am angry !\n<p>Admin</p>\n'
110 _attachments = [
111 {'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
112 {'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}
113
114=== modified file 'fetchmail/fetchmail.py'
115--- fetchmail/fetchmail.py 2012-10-25 13:09:30 +0000
116+++ fetchmail/fetchmail.py 2012-11-14 14:39:22 +0000
117@@ -243,20 +243,20 @@
118
119 def create(self, cr, uid, values, context=None):
120 if context is None:
121- context={}
122+ context = {}
123 fetchmail_server_id = context.get('fetchmail_server_id')
124 if fetchmail_server_id:
125 values['fetchmail_server_id'] = fetchmail_server_id
126- res = super(mail_mail,self).create(cr, uid, values, context=context)
127+ res = super(mail_mail, self).create(cr, uid, values, context=context)
128 return res
129
130 def write(self, cr, uid, ids, values, context=None):
131 if context is None:
132- context={}
133+ context = {}
134 fetchmail_server_id = context.get('fetchmail_server_id')
135 if fetchmail_server_id:
136- values['fetchmail_server_id'] = server_id
137- res = super(mail_mail,self).write(cr, uid, ids, values, context=context)
138+ values['fetchmail_server_id'] = fetchmail_server_id
139+ res = super(mail_mail, self).write(cr, uid, ids, values, context=context)
140 return res
141
142
143
144=== modified file 'hr/hr_data.xml'
145--- hr/hr_data.xml 2012-08-30 14:18:52 +0000
146+++ hr/hr_data.xml 2012-11-14 14:39:22 +0000
147@@ -6,11 +6,11 @@
148 <field name="model">mail.group</field>
149 <field name="res_id" ref="mail.group_all_employees"/>
150 <field name="type">notification</field>
151+ <field name="subtype_id" ref="mail.mt_comment"/>
152 <field name="subject">Employee Directory application installed!</field>
153- <field name="body">Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.
154-
155-More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
156-Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</field>
157+ <field name="body"><![CDATA[<p>Manage your human resources with OpenERP: employees and their hierarchy, HR departments and job positions.</p>
158+<p>More HR features are available via extra applications: Recruitment Process (manage job positions and recruitment), Timesheet Validation (record timesheets and attendance),
159+Leave Management (keep track of employee leaves), Expense Management (manage employee expenses), Employee Appraisals (organize employee surveys, where employees evaluate their subordinates or their manager).</p>]]></field>
160 </record>
161
162 <record id="employee" model="hr.employee">
163
164=== modified file 'hr_evaluation/hr_evaluation_data.xml'
165--- hr_evaluation/hr_evaluation_data.xml 2012-09-20 09:09:11 +0000
166+++ hr_evaluation/hr_evaluation_data.xml 2012-11-14 14:39:22 +0000
167@@ -11,9 +11,9 @@
168 <field name="model">mail.group</field>
169 <field name="res_id" ref="mail.group_all_employees"/>
170 <field name="type">notification</field>
171+ <field name="subtype_id" ref="mail.mt_comment"/>
172 <field name="subject">Employee Appraisals application installed!</field>
173- <field name="body">Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels.
174-Evaluations filled by employees may be exported as pdf files.</field>
175+ <field name="body"><![CDATA[<p>Manage employee reviews: you can define an appraisal campaign with several steps, with specific evaluation surveys according to hierarchy levels. Evaluations filled by employees may be exported as pdf files.</p>]]></field>
176 </record>
177
178 <record id="survey_2" model="survey">
179
180=== modified file 'hr_expense/hr_expense_data.xml'
181--- hr_expense/hr_expense_data.xml 2012-08-30 14:18:52 +0000
182+++ hr_expense/hr_expense_data.xml 2012-11-14 14:39:22 +0000
183@@ -6,10 +6,10 @@
184 <field name="model">mail.group</field>
185 <field name="res_id" ref="mail.group_all_employees"/>
186 <field name="type">notification</field>
187+ <field name="subtype_id" ref="mail.mt_comment"/>
188 <field name="subject">Expense Management application installed!</field>
189- <field name="body">Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.
190-
191-This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</field>
192+ <field name="body"><![CDATA[<p>Manage your employees' expenses, after due validation by their manager and the accountant, then generate and pay the corresponding invoices.</p>
193+<p>This feature is also linked to analytic accounting and compatible with timesheet invoices, so you will be able to automatically re-invoice project-related expenses to your customers.</p>]]></field>
194 </record>
195
196 <!-- Resource: product.uom.categ -->
197
198=== modified file 'hr_holidays/hr_holidays_data.xml'
199--- hr_holidays/hr_holidays_data.xml 2012-10-02 20:40:23 +0000
200+++ hr_holidays/hr_holidays_data.xml 2012-11-14 14:39:22 +0000
201@@ -11,9 +11,10 @@
202 <field name="model">mail.group</field>
203 <field name="res_id" ref="mail.group_all_employees"/>
204 <field name="type">notification</field>
205+ <field name="subtype_id" ref="mail.mt_comment"/>
206 <field name="subject">Leave Management application installed!</field>
207- <field name="body">Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.
208-Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</field>
209+ <field name="body"><![CDATA[<p>Manage employee leaves from the top menu "Human Resources". Employees can create leave requests that are validated by their manager and/or HR officers.</p>
210+<p>Once validated, they are visible in the employee's calendar. HR officers can define leave types and allocate leaves to employees and employee categories.</p>]]></field>
211 </record>
212
213
214
215=== modified file 'hr_recruitment/hr_recruitment_data.xml'
216--- hr_recruitment/hr_recruitment_data.xml 2012-10-08 09:50:03 +0000
217+++ hr_recruitment/hr_recruitment_data.xml 2012-11-14 14:39:22 +0000
218@@ -6,10 +6,10 @@
219 <field name="model">mail.group</field>
220 <field name="res_id" ref="mail.group_all_employees"/>
221 <field name="type">notification</field>
222+ <field name="subtype_id" ref="mail.mt_comment"/>
223 <field name="subject">Recruitment Process application installed!</field>
224- <field name="body">Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.
225-
226-You can automatically receive job application though an email gateway, see the Human Resources settings.</field>
227+ <field name="body"><![CDATA[<p>Manage job positions and your company's recruitment process. This application is integrated with the Survey application to help you define interviews for different jobs.</p>
228+<p>You can automatically receive job application though an email gateway, see the Human Resources settings.</p>]]></field>
229 </record>
230
231 <!-- Meeting Types (for interview meetings) -->
232
233=== modified file 'hr_timesheet_sheet/hr_timesheet_sheet_data.xml'
234--- hr_timesheet_sheet/hr_timesheet_sheet_data.xml 2012-09-24 08:23:00 +0000
235+++ hr_timesheet_sheet/hr_timesheet_sheet_data.xml 2012-11-14 14:39:22 +0000
236@@ -6,8 +6,9 @@
237 <field name="model">mail.group</field>
238 <field name="res_id" ref="mail.group_all_employees"/>
239 <field name="type">notification</field>
240+ <field name="subtype_id" ref="mail.mt_comment"/>
241 <field name="subject">Timesheet Validation application installed!</field>
242- <field name="body">From the top menu "Human Resources", enter and validate timesheets and attendances.</field>
243+ <field name="body"><![CDATA[<p>From the top menu "Human Resources", enter and validate timesheets and attendances.</p>]]></field>
244 </record>
245
246 <record id="ir_actions_server_timsheet_sheet" model="ir.actions.server">
247
248=== modified file 'mail/data/mail_demo.xml'
249--- mail/data/mail_demo.xml 2012-11-12 15:27:53 +0000
250+++ mail/data/mail_demo.xml 2012-11-14 14:39:22 +0000
251@@ -11,44 +11,48 @@
252 <record id="message_blogpost0" model="mail.message">
253 <field name="model">mail.group</field>
254 <field name="res_id" ref="mail.group_all_employees"/>
255- <field name="body">Your monthly meal vouchers arrived. You can get them at Christine's office.
256-This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.</field>
257+ <field name="body"><![CDATA[<p>Your monthly meal vouchers arrived. You can get them at Christine's office.</p>]]></field>
258 <field name="type">comment</field>
259 <field name="subtype_id" ref="mt_comment"/>
260+ <field name="author_id" ref="base.partner_root"/>
261 </record>
262 <record id="message_blogpost0_comment0" model="mail.message">
263 <field name="model">mail.group</field>
264 <field name="res_id" ref="group_all_employees"/>
265- <field name="body"><![CDATA[Great.]]></field>
266+ <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>
267 <field name="parent_id" ref="message_blogpost0"/>
268 <field name="type">comment</field>
269 <field name="subtype_id" ref="mt_comment"/>
270+ <field name="author_id" ref="base.partner_root"/>
271 </record>
272 <record id="message_blogpost0_comment1" model="mail.message">
273 <field name="model">mail.group</field>
274 <field name="res_id" ref="group_all_employees"/>
275- <field name="body">Thanks, but where is Christine's office, if I may ask? (I'm new here)</field>
276+ <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>
277 <field name="parent_id" ref="message_blogpost0"/>
278 <field name="type">comment</field>
279 <field name="subtype_id" ref="mt_comment"/>
280+ <field name="author_id" ref="base.partner_demo"/>
281 </record>
282 <!-- This one is starred for having mailboxes with demo data -->
283 <record id="message_blogpost0_comment2" model="mail.message">
284 <field name="model">mail.group</field>
285 <field name="res_id" ref="group_all_employees"/>
286- <field name="body">Building B3, second floor on the right :-)</field>
287+ <field name="body"><![CDATA[<p>Building B3, second floor on the right :-).</p>]]></field>
288 <field name="parent_id" ref="message_blogpost0"/>
289 <field name="type">comment</field>
290 <field name="subtype_id" ref="mt_comment"/>
291+ <field name="author_id" ref="base.partner_root"/>
292 <field name="favorite_user_ids" eval="[(6, 0, [ref('base.user_root'), ref('base.user_demo')])]"/>
293 </record>
294 <record id="message_blogpost0_comment3" model="mail.message">
295 <field name="model">mail.group</field>
296 <field name="res_id" ref="group_all_employees"/>
297- <field name="body">Great news, I need to buy a new fridge, I think I can pay it with the eco-vouchers!</field>
298+ <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>
299 <field name="parent_id" ref="message_blogpost0"/>
300 <field name="type">comment</field>
301 <field name="subtype_id" ref="mt_comment"/>
302+ <field name="author_id" ref="base.partner_demo"/>
303 </record>
304
305 <!-- Demo user and admin conversation -->
306
307=== modified file 'mail/data/mail_group_data.xml'
308--- mail/data/mail_group_data.xml 2012-11-12 23:04:18 +0000
309+++ mail/data/mail_group_data.xml 2012-11-14 14:39:22 +0000
310@@ -17,12 +17,11 @@
311 <field name="model">mail.group</field>
312 <field name="res_id" ref="mail.group_all_employees"/>
313 <field name="type">notification</field>
314+ <field name="subtype_id" ref="mail.mt_comment"/>
315 <field name="subject">Welcome to OpenERP!</field>
316- <field name="body">Your homepage is a summary of messages you received and key information about documents you follow.
317-
318-The 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.
319-
320-To setup your preferences (name, email signature, avatar), click on the top right corner.</field>
321+ <field name="body"><![CDATA[<p>Your homepage is a summary of messages you received and key information about documents you follow.<br />
322+The 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 />
323+To setup your preferences (name, email signature, avatar), click on the top right corner.</p>]]></field>
324 </record>
325 </data>
326 </openerp>
327
328=== modified file 'mail/mail_followers.py'
329--- mail/mail_followers.py 2012-11-12 13:17:59 +0000
330+++ mail/mail_followers.py 2012-11-14 14:39:22 +0000
331@@ -84,11 +84,13 @@
332 return False
333
334 def set_message_read(self, cr, uid, msg_ids, read=None, context=None):
335- """ Set a message and its child messages as (un)read for uid.
336+ """ Set messages as (un)read. Technically, the notifications related
337+ to uid are set to (un)read. If for some msg_ids there are missing
338+ notifications (i.e. due to load more or thread parent fetching),
339+ they are created.
340
341- :param bool read: read / unread
342+ :param bool read: (un)read notification
343 """
344- # TDE note: use child_of or front-end send correct values ?
345 user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
346 notif_ids = self.search(cr, uid, [
347 ('partner_id', '=', user_pid),
348@@ -100,10 +102,9 @@
349 return self.write(cr, uid, notif_ids, {'read': read}, context=context)
350
351 # some messages do not have notifications: find which one, create notification, update read status
352- exist_notification = dict.fromkeys(msg_ids, False)
353- for notification in self.browse(cr, uid, notif_ids, context=context):
354- exist_notification[notification.message_id.id] = True
355- for msg_id in exist_notification.keys():
356+ notified_msg_ids = [notification.message_id.id for notification in self.browse(cr, uid, notif_ids, context=context)]
357+ to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids))
358+ for msg_id in to_create_msg_ids:
359 self.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context)
360 return self.write(cr, uid, notif_ids, {'read': read}, context=context)
361
362@@ -156,10 +157,10 @@
363 # add signature
364 body_html = msg.body
365 # if quote_context:
366- # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
367- signature = msg.author_id and msg.author_id.user_ids[0].signature or ''
368+ # body_html = tools.append_content_to_html(body_html, quote_context, plaintext=False)
369+ signature = msg.author_id and msg.author_id.user_ids and msg.author_id.user_ids[0].signature or ''
370 if signature:
371- body_html = tools.append_content_to_html(body_html, signature)
372+ body_html = tools.append_content_to_html(body_html, signature, plaintext=True, container_tag='div')
373
374 mail_values = {
375 'mail_message_id': msg.id,
376
377=== modified file 'mail/mail_message.py'
378--- mail/mail_message.py 2012-11-12 14:04:08 +0000
379+++ mail/mail_message.py 2012-11-14 14:39:22 +0000
380@@ -25,6 +25,7 @@
381 from email.header import decode_header
382 from openerp import SUPERUSER_ID
383 from openerp.osv import osv, orm, fields
384+from openerp.tools import html_email_clean
385 from openerp.tools.translate import _
386
387 _logger = logging.getLogger(__name__)
388@@ -280,7 +281,7 @@
389
390 return {'id': message.id,
391 'type': message.type,
392- 'body': message.body,
393+ 'body': html_email_clean(message.body),
394 'model': message.model,
395 'res_id': message.res_id,
396 'record_name': message.record_name,
397@@ -633,6 +634,8 @@
398 def create(self, cr, uid, values, context=None):
399 if not values.get('message_id') and values.get('res_id') and values.get('model'):
400 values['message_id'] = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values)
401+ elif not values.get('message_id'):
402+ values['message_id'] = tools.generate_tracking_message_id('private')
403 newid = super(mail_message, self).create(cr, uid, values, context)
404 self._notify(cr, SUPERUSER_ID, newid, context=context)
405 return newid
406@@ -763,7 +766,7 @@
407 ], context=context)
408 fol_objs = fol_obj.read(cr, uid, fol_ids, ['partner_id'], context=context)
409 partners_to_notify |= set(fol['partner_id'][0] for fol in fol_objs)
410- # when writing to a wall
411+ # remove me from notified partners, unless the message is written on my own wall
412 if message.get('author_id') and message.get('model') == "res.partner" and message.get('res_id') == message.get('author_id')[0]:
413 partners_to_notify |= set([message.get('author_id')[0]])
414 elif message.get('author_id'):
415
416=== modified file 'mail/mail_thread.py'
417--- mail/mail_thread.py 2012-11-12 13:10:51 +0000
418+++ mail/mail_thread.py 2012-11-14 14:39:22 +0000
419@@ -319,10 +319,12 @@
420 """
421 assert isinstance(message, Message), 'message must be an email.message.Message at this point'
422 message_id = message.get('Message-Id')
423+ references = decode_header(message, 'References')
424+ in_reply_to = decode_header(message, 'In-Reply-To')
425
426 # 1. Verify if this is a reply to an existing thread
427- references = decode_header(message, 'References') or decode_header(message, 'In-Reply-To')
428- ref_match = references and tools.reference_re.search(references)
429+ thread_references = references or in_reply_to
430+ ref_match = thread_references and tools.reference_re.search(thread_references)
431 if ref_match:
432 thread_id = int(ref_match.group(1))
433 model = ref_match.group(2) or model
434@@ -333,6 +335,14 @@
435 message_id, model, thread_id, custom_values, uid)
436 return [(model, thread_id, custom_values, uid)]
437
438+ # Verify this is a reply to a private message
439+ message_ids = self.pool.get('mail.message').search(cr, uid, [('message_id', '=', in_reply_to)], limit=1, context=context)
440+ if message_ids:
441+ message = self.pool.get('mail.message').browse(cr, uid, message_ids[0], context=context)
442+ _logger.debug('Routing mail with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
443+ message_id, message.id, custom_values, uid)
444+ return [(False, 0, custom_values, uid)]
445+
446 # 2. Look for a matching mail.alias entry
447 # Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
448 # for all the odd MTAs out there, as there is no standard header for the envelope's `rcpt_to` value.
449@@ -376,14 +386,19 @@
450 def message_process(self, cr, uid, model, message, custom_values=None,
451 save_original=False, strip_attachments=False,
452 thread_id=None, context=None):
453- """Process an incoming RFC2822 email message, relying on
454- ``mail.message.parse()`` for the parsing operation,
455- and ``message_route()`` to figure out the target model.
456+ """ Process an incoming RFC2822 email message, relying on
457+ ``mail.message.parse()`` for the parsing operation,
458+ and ``message_route()`` to figure out the target model.
459
460- Once the target model is known, its ``message_new`` method
461- is called with the new message (if the thread record did not exist)
462+ Once the target model is known, its ``message_new`` method
463+ is called with the new message (if the thread record did not exist)
464 or its ``message_update`` method (if it did).
465
466+ There is a special case where the target model is False: a reply
467+ to a private message. In this case, we skip the message_new /
468+ message_update step, to just post a new message using mail_thread
469+ message_post.
470+
471 :param string model: the fallback model to use if the message
472 does not match any of the currently configured mail aliases
473 (may be None if a matching alias is supposed to be present)
474@@ -425,15 +440,19 @@
475 for model, thread_id, custom_values, user_id in routes:
476 if self._name != model:
477 context.update({'thread_model': model})
478- model_pool = self.pool.get(model)
479- assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
480- "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
481- (msg['message_id'], model)
482- if thread_id and hasattr(model_pool, 'message_update'):
483- model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
484+ if model:
485+ model_pool = self.pool.get(model)
486+ assert thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new'), \
487+ "Undeliverable mail with Message-Id %s, model %s does not accept incoming emails" % \
488+ (msg['message_id'], model)
489+ if thread_id and hasattr(model_pool, 'message_update'):
490+ model_pool.message_update(cr, user_id, [thread_id], msg, context=context)
491+ else:
492+ thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
493 else:
494- thread_id = model_pool.message_new(cr, user_id, msg, custom_values, context=context)
495- model_pool.message_post(cr, uid, [thread_id], context=context, **msg)
496+ assert thread_id == 0, "Posting a message without model should be with a null res_id, to create a private message."
497+ model_pool = self.pool.get('mail.thread')
498+ model_pool.message_post_user_api(cr, uid, [thread_id], context=context, content_subtype='html', **msg)
499 return thread_id
500
501 def message_new(self, cr, uid, msg_dict, custom_values=None, context=None):
502@@ -501,7 +520,7 @@
503 body = tools.ustr(body, encoding, errors='replace')
504 if message.get_content_type() == 'text/plain':
505 # text/plain -> <pre/>
506- body = tools.append_content_to_html(u'', body)
507+ body = tools.append_content_to_html(u'', body, preserve=True)
508 else:
509 alternative = (message.get_content_type() == 'multipart/alternative')
510 for part in message.walk():
511@@ -516,7 +535,7 @@
512 # 2) text/plain -> <pre/>
513 if part.get_content_type() == 'text/plain' and (not alternative or not body):
514 body = tools.append_content_to_html(body, tools.ustr(part.get_payload(decode=True),
515- encoding, errors='replace'))
516+ encoding, errors='replace'), preserve=True)
517 # 3) text/html -> raw
518 elif part.get_content_type() == 'text/html':
519 html = tools.ustr(part.get_payload(decode=True), encoding, errors='replace')
520@@ -556,7 +575,6 @@
521 """
522 msg_dict = {
523 'type': 'email',
524- 'subtype': 'mail.mt_comment',
525 'author_id': False,
526 }
527 if not isinstance(message, Message):
528@@ -588,7 +606,7 @@
529 else:
530 msg_dict['email_from'] = message.get('from')
531 partner_ids = self._message_find_partners(cr, uid, message, ['From', 'To', 'Cc'], context=context)
532- msg_dict['partner_ids'] = partner_ids
533+ msg_dict['partner_ids'] = [(4, partner_id) for partner_id in partner_ids]
534
535 if 'Date' in message:
536 date_hdr = decode(message.get('Date'))
537@@ -629,7 +647,8 @@
538 mail.message ID. Extra keyword arguments will be used as default
539 column values for the new mail.message record.
540 Auto link messages for same id and object
541- :param int thread_id: thread ID to post into, or list with one ID
542+ :param int thread_id: thread ID to post into, or list with one ID;
543+ if False/0, mail.message model will also be set as False
544 :param str body: body of the message, usually raw HTML that will
545 be sanitized
546 :param str subject: optional subject
547@@ -639,10 +658,13 @@
548 ``(name,content)``, where content is NOT base64 encoded
549 :return: ID of newly created mail.message
550 """
551- context = context or {}
552- attachments = attachments or []
553+ if context is None:
554+ context = {}
555+ if attachments is None:
556+ attachments = {}
557+
558 assert (not thread_id) or isinstance(thread_id, (int, long)) or \
559- (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id"
560+ (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"
561 if isinstance(thread_id, (list, tuple)):
562 thread_id = thread_id and thread_id[0]
563 mail_message = self.pool.get('mail.message')
564@@ -682,7 +704,6 @@
565 # avoid loops when finding ancestors
566 processed_list = []
567 if message_ids:
568- _counter, _counter_max = 0, 200
569 message = mail_message.browse(cr, SUPERUSER_ID, message_ids[0], context=context)
570 while (message.parent_id and message.parent_id.id not in processed_list):
571 processed_list.append(message.parent_id.id)
572@@ -707,18 +728,45 @@
573
574 return mail_message.create(cr, uid, values, context=context)
575
576- def message_post_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False, attachment_ids=None, context=None):
577- """ Wrapper on message_post, used only in Chatter (JS). The purpose is
578- to handle attachments.
579- # TDE FIXME: body is plaintext: convert it into html
580+ def message_post_user_api(self, cr, uid, thread_id, body='', subject=False, parent_id=False,
581+ attachment_ids=None, context=None, content_subtype='plaintext', **kwargs):
582+ """ Wrapper on message_post, used for user input :
583+ - mail gateway
584+ - quick reply in Chatter (refer to mail.js), not
585+ the mail.compose.message wizard
586+ The purpose is to perform some pre- and post-processing:
587+ - if body is plaintext: convert it into html
588+ - if parent_id: handle reply to a previous message by adding the
589+ parent partners to the message
590+ - type and subtype: comment and mail.mt_comment by default
591+ - attachment_ids: supposed not attached to any document; attach them
592+ to the related document. Should only be set by Chatter.
593 """
594- new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type='comment',
595- subtype='mail.mt_comment', parent_id=parent_id, context=context)
596-
597- # HACK FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
598+ ir_attachment = self.pool.get('ir.attachment')
599+ mail_message = self.pool.get('mail.message')
600+
601+ # 1. Pre-processing: body, partner_ids, type and subtype
602+ if content_subtype == 'plaintext':
603+ body = tools.text2html(body)
604+
605+ partner_ids = kwargs.pop('partner_ids', [])
606+ if parent_id:
607+ parent_message = self.pool.get('mail.message').browse(cr, uid, parent_id, context=context)
608+ partner_ids += [(4, partner.id) for partner in parent_message.partner_ids]
609+ # TDE FIXME HACK: mail.thread -> private message
610+ if self._name == 'mail.thread' and parent_message.author_id.id:
611+ partner_ids.append((4, parent_message.author_id.id))
612+
613+ message_type = kwargs.pop('type', 'comment')
614+ message_subtype = kwargs.pop('subtype', 'mail.mt_comment')
615+
616+ # 2. Post message
617+ new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type,
618+ subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs)
619+
620+ # 3. Post-processing
621+ # HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message
622 if attachment_ids:
623- ir_attachment = self.pool.get('ir.attachment')
624- mail_message = self.pool.get('mail.message')
625 filtered_attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [
626 ('res_model', '=', 'mail.compose.message'),
627 ('res_id', '=', 0),
628
629=== modified file 'mail/res_partner.py'
630--- mail/res_partner.py 2012-10-15 13:23:13 +0000
631+++ mail/res_partner.py 2012-11-14 14:39:22 +0000
632@@ -42,4 +42,22 @@
633 'notification_email_send': lambda *args: 'comment'
634 }
635
636+ def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification',
637+ subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
638+ """ Override related to res.partner. In case of email message, set it as
639+ private:
640+ - add the target partner in the message partner_ids
641+ - set thread_id as None, because this will trigger the 'private'
642+ aspect of the message (model=False, res_id=False)
643+ """
644+ if isinstance(thread_id, (list, tuple)):
645+ thread_id = thread_id[0]
646+ if type == 'email':
647+ partner_ids = kwargs.get('partner_ids', [])
648+ if thread_id not in partner_ids:
649+ partner_ids.append(thread_id)
650+ kwargs['partner_ids'] = partner_ids
651+ return super(res_partner_mail, self).message_post(cr, uid, False, body=body, subject=subject,
652+ type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, **kwargs)
653+
654 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
655
656=== modified file 'mail/security/ir.model.access.csv'
657--- mail/security/ir.model.access.csv 2012-11-06 15:04:31 +0000
658+++ mail/security/ir.model.access.csv 2012-11-14 14:39:22 +0000
659@@ -7,12 +7,13 @@
660 access_mail_followers_all,mail.followers.all,model_mail_followers,,1,0,0,0
661 access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1
662 access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0
663-access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
664+access_mail_notification_group_user,mail.notification.user,model_mail_notification,base.group_user,1,1,1,0
665+access_mail_notification_system,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1
666 access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0
667 access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1
668 access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0
669-access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0
670-access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1
671+access_mail_alias_user,mail.alias.user,model_mail_alias,base.group_user,1,1,1,0
672+access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1
673 access_mail_message_subtype_all,mail.message.subtype.all,model_mail_message_subtype,,1,0,0,0
674 access_mail_vote_all,mail.vote.all,model_mail_vote,,1,1,1,1
675 access_mail_favorite_all,mail.favorite.all,model_mail_favorite,,1,1,1,1
676
677=== modified file 'mail/security/mail_security.xml'
678--- mail/security/mail_security.xml 2012-10-19 09:59:19 +0000
679+++ mail/security/mail_security.xml 2012-11-14 14:39:22 +0000
680@@ -10,7 +10,7 @@
681 <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>
682 </record>
683
684- <record id="mail_followers_read_own" model="ir.rule">
685+ <record id="mail_followers_read_write_own" model="ir.rule">
686 <field name="name">mail.followers: read and write its own entries</field>
687 <field name="model_id" ref="model_mail_followers"/>
688 <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
689@@ -18,6 +18,14 @@
690 <field name="perm_unlink" eval="False"/>
691 </record>
692
693+ <record id="mail_notification_read_write_own" model="ir.rule">
694+ <field name="name">mail.notification: read and write its own entries</field>
695+ <field name="model_id" ref="model_mail_notification"/>
696+ <field name="domain_force">[('partner_id', '=', user.partner_id.id)]</field>
697+ <field name="perm_create" eval="False"/>
698+ <field name="perm_unlink" eval="False"/>
699+ </record>
700+
701 <!--
702 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.
703 <record id="mail_message_read_partner_or_author" model="ir.rule">
704
705=== modified file 'mail/static/src/css/mail.css'
706--- mail/static/src/css/mail.css 2012-11-13 10:35:30 +0000
707+++ mail/static/src/css/mail.css 2012-11-14 14:39:22 +0000
708@@ -87,6 +87,10 @@
709 margin-bottom: 0px;
710 margin-top: 2px;
711 }
712+.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p{
713+ margin-top: 0px;
714+ margin-bottom: 0px;
715+}
716
717 /* a) Indented Messages */
718
719
720=== modified file 'mail/static/src/js/mail.js'
721--- mail/static/src/js/mail.js 2012-11-13 14:57:22 +0000
722+++ mail/static/src/js/mail.js 2012-11-14 14:39:22 +0000
723@@ -590,7 +590,7 @@
724
725 if (body.match(/\S+/)) {
726 //session.web.blockUI();
727- this.parent_thread.ds_thread.call('message_post_api', [
728+ this.parent_thread.ds_thread.call('message_post_user_api', [
729 this.context.default_res_id,
730 mail.ChatterUtils.get_text2html(body),
731 false,
732@@ -728,7 +728,6 @@
733
734 mail.ThreadMessage = mail.MessageCommon.extend({
735 template: 'mail.thread.message',
736-
737
738 start: function () {
739 this._super.apply(this, arguments);
740
741=== modified file 'mail/tests/__init__.py'
742--- mail/tests/__init__.py 2012-09-14 11:58:15 +0000
743+++ mail/tests/__init__.py 2012-11-14 14:39:22 +0000
744@@ -18,6 +18,7 @@
745 # along with this program. If not, see <http://www.gnu.org/licenses/>.
746 #
747 ##############################################################################
748+
749 from . import test_mail, test_mail_access_rights
750
751 checks = [
752
753=== modified file 'mail/tests/test_mail.py'
754--- mail/tests/test_mail.py 2012-11-09 15:11:22 +0000
755+++ mail/tests/test_mail.py 2012-11-14 14:39:22 +0000
756@@ -21,8 +21,8 @@
757
758 import tools
759
760-from openerp.tests import common
761-from openerp.tools.html_sanitize import html_sanitize
762+from openerp.addons.mail.tests import test_mail_mockup
763+from openerp.tools.mail import html_sanitize
764
765 MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
766 To: {to}
767@@ -84,43 +84,11 @@
768 """
769
770
771-class TestMailMockups(common.TransactionCase):
772-
773- def _mock_smtp_gateway(self, *args, **kwargs):
774- return True
775-
776- def _init_mock_build_email(self):
777- self._build_email_args_list = []
778- self._build_email_kwargs_list = []
779-
780- def _mock_build_email(self, *args, **kwargs):
781- """ Mock build_email to be able to test its values. Store them into
782- some internal variable for latter processing. """
783- self._build_email_args_list.append(args)
784- self._build_email_kwargs_list.append(kwargs)
785- return self._build_email(*args, **kwargs)
786-
787- def setUp(self):
788- super(TestMailMockups, self).setUp()
789- # Install mock SMTP gateway
790- self._init_mock_build_email()
791- self._build_email = self.registry('ir.mail_server').build_email
792- self.registry('ir.mail_server').build_email = self._mock_build_email
793- self._send_email = self.registry('ir.mail_server').send_email
794- self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
795-
796- def tearDown(self):
797- # Remove mocks
798- self.registry('ir.mail_server').build_email = self._build_email
799- self.registry('ir.mail_server').send_email = self._send_email
800- super(TestMailMockups, self).tearDown()
801-
802-
803-class test_mail(TestMailMockups):
804+class test_mail(test_mail_mockup.TestMailMockups):
805
806 def _mock_send_get_mail_body(self, *args, **kwargs):
807 # def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
808- body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner')
809+ body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner', plaintext=False)
810 return body
811
812 def setUp(self):
813@@ -375,10 +343,10 @@
814 _subject = 'Pigs'
815 _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
816 _body1 = 'Pigs rules'
817- _mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'
818- _mail_bodyalt1 = 'Pigs rules\nAdmin'
819+ _mail_body1 = 'Pigs rules\n<div><p>Admin</p></div>\n'
820+ _mail_bodyalt1 = 'Pigs rules\nAdmin\n'
821 _body2 = '<html>Pigs rules</html>'
822- _mail_body2 = html_sanitize('<html>Pigs rules\n<pre>Admin</pre>\n</html>')
823+ _mail_body2 = html_sanitize('<html>Pigs rules\n<div><p>Admin</p></div>\n</html>')
824 _mail_bodyalt2 = 'Pigs rules\nAdmin'
825 _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
826
827@@ -399,7 +367,7 @@
828 # Test: sent_email: email send by server: correct subject, body, body_alternative
829 for sent_email in sent_emails:
830 self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
831- self.assertEqual(sent_email['body'], _mail_body1 + '\n<pre>Bert Tartopoils</pre>\n', 'sent_email body incorrect')
832+ self.assertEqual(sent_email['body'], _mail_body1 + '\nBert Tartopoils\n', 'sent_email body incorrect')
833 # the html2plaintext uses etree or beautiful soup, so the result may be slighly different
834 # depending if you have installed beautiful soup.
835 self.assertIn(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils\n', 'sent_email body_alternative is incorrect')
836
837=== modified file 'mail/tests/test_mail_access_rights.py'
838--- mail/tests/test_mail_access_rights.py 2012-10-25 11:30:48 +0000
839+++ mail/tests/test_mail_access_rights.py 2012-11-14 14:39:22 +0000
840@@ -19,11 +19,11 @@
841 #
842 ##############################################################################
843
844-from openerp.addons.mail.tests import test_mail
845+from openerp.addons.mail.tests import test_mail_mockup
846 from osv.orm import except_orm
847
848
849-class test_mail_access_rights(test_mail.TestMailMockups):
850+class test_mail_access_rights(test_mail_mockup.TestMailMockups):
851
852 def setUp(self):
853 super(test_mail_access_rights, self).setUp()
854
855=== added file 'mail/tests/test_mail_mockup.py'
856--- mail/tests/test_mail_mockup.py 1970-01-01 00:00:00 +0000
857+++ mail/tests/test_mail_mockup.py 2012-11-14 14:39:22 +0000
858@@ -0,0 +1,54 @@
859+# -*- coding: utf-8 -*-
860+##############################################################################
861+#
862+# OpenERP, Open Source Business Applications
863+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
864+#
865+# This program is free software: you can redistribute it and/or modify
866+# it under the terms of the GNU Affero General Public License as
867+# published by the Free Software Foundation, either version 3 of the
868+# License, or (at your option) any later version.
869+#
870+# This program is distributed in the hope that it will be useful,
871+# but WITHOUT ANY WARRANTY; without even the implied warranty of
872+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
873+# GNU Affero General Public License for more details.
874+#
875+# You should have received a copy of the GNU Affero General Public License
876+# along with this program. If not, see <http://www.gnu.org/licenses/>.
877+#
878+##############################################################################
879+
880+from openerp.tests import common
881+
882+
883+class TestMailMockups(common.TransactionCase):
884+
885+ def _mock_smtp_gateway(self, *args, **kwargs):
886+ return True
887+
888+ def _init_mock_build_email(self):
889+ self._build_email_args_list = []
890+ self._build_email_kwargs_list = []
891+
892+ def _mock_build_email(self, *args, **kwargs):
893+ """ Mock build_email to be able to test its values. Store them into
894+ some internal variable for latter processing. """
895+ self._build_email_args_list.append(args)
896+ self._build_email_kwargs_list.append(kwargs)
897+ return self._build_email(*args, **kwargs)
898+
899+ def setUp(self):
900+ super(TestMailMockups, self).setUp()
901+ # Install mock SMTP gateway
902+ self._init_mock_build_email()
903+ self._build_email = self.registry('ir.mail_server').build_email
904+ self.registry('ir.mail_server').build_email = self._mock_build_email
905+ self._send_email = self.registry('ir.mail_server').send_email
906+ self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
907+
908+ def tearDown(self):
909+ # Remove mocks
910+ self.registry('ir.mail_server').build_email = self._build_email
911+ self.registry('ir.mail_server').send_email = self._send_email
912+ super(TestMailMockups, self).tearDown()
913
914=== modified file 'mrp/mrp_data.xml'
915--- mrp/mrp_data.xml 2012-10-02 20:40:23 +0000
916+++ mrp/mrp_data.xml 2012-11-14 14:39:22 +0000
917@@ -6,11 +6,11 @@
918 <field name="model">mail.group</field>
919 <field name="res_id" ref="mail.group_all_employees"/>
920 <field name="type">notification</field>
921+ <field name="subtype_id" ref="mail.mt_comment"/>
922 <field name="subject">MRP application installed!</field>
923- <field name="body">Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.
924-This application supports complete integration and production scheduling for stockable goods, consumables, and services.
925-
926-From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</field>
927+ <field name="body"><![CDATA[<p>Manage your manufacturing process with OpenERP by defining your bills of materials (BoM), routings and work centers.<br />
928+This application supports complete integration and production scheduling for stockable goods, consumables, and services.</p>
929+<p>From the Manufacturing Settings, you can choose to compute production schedules periodically or just-in-time.</p>]]></field>
930 </record>
931
932 <record id="sequence_mrp_prod_type" model="ir.sequence.type">
933
934=== modified file 'note/note.py'
935--- note/note.py 2012-11-02 13:17:59 +0000
936+++ note/note.py 2012-11-14 14:39:22 +0000
937@@ -20,9 +20,7 @@
938 ##############################################################################
939
940 from openerp.osv import osv, fields
941-from tools.translate import _
942-import re
943-from openerp.tools.misc import html2plaintext
944+from openerp.tools import html2plaintext
945
946 class note_stage(osv.osv):
947 """ Category of Note """
948
949=== modified file 'pad/pad.py'
950--- pad/pad.py 2012-11-09 06:30:02 +0000
951+++ pad/pad.py 2012-11-14 14:39:22 +0000
952@@ -6,7 +6,7 @@
953 import urllib2
954 import logging
955 from tools.translate import _
956-from openerp.tools.misc import html2plaintext
957+from openerp.tools import html2plaintext
958 from py_etherpad import EtherpadLiteClient
959
960 _logger = logging.getLogger(__name__)
961
962=== modified file 'point_of_sale/point_of_sale_data.xml'
963--- point_of_sale/point_of_sale_data.xml 2012-09-16 11:42:49 +0000
964+++ point_of_sale/point_of_sale_data.xml 2012-11-14 14:39:22 +0000
965@@ -20,10 +20,10 @@
966 <field name="model">mail.group</field>
967 <field name="res_id" ref="mail.group_all_employees"/>
968 <field name="type">notification</field>
969+ <field name="subtype_id" ref="mail.mt_comment"/>
970 <field name="subject">Point of Sale application installed!</field>
971- <field name="body">Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.
972-
973-If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.</field>
974+ <field name="body"><![CDATA[<p>Record sale orders, register payments, compute change to return, create invoices, and manage refunds through a specific web touch-screen interface.</p>
975+<p>If you install the PoS proxy you will be able to interface OpenERP with retail hardware: barcode scanners, printers, cash registers, weighing machines, credit card payment terminals.</p>]]></field>
976 </record>
977
978 <record id="unreferenced_product" model="product.product">
979
980=== modified file 'portal/mail_mail.py'
981--- portal/mail_mail.py 2012-10-01 09:14:41 +0000
982+++ portal/mail_mail.py 2012-11-14 14:39:22 +0000
983@@ -36,5 +36,5 @@
984 if partner:
985 context = dict(context or {}, signup_valid=True)
986 partner = self.pool.get('res.partner').browse(cr, uid, partner.id, context)
987- body = tools.append_content_to_html(body, "Log in our portal at: %s" % partner.signup_url)
988+ body = tools.append_content_to_html(body, ("<div><p>Log in our portal at: %s</p></div>" % partner.signup_url), plaintext=False)
989 return body
990
991=== modified file 'portal/portal_demo.xml'
992--- portal/portal_demo.xml 2012-09-20 14:57:53 +0000
993+++ portal/portal_demo.xml 2012-11-14 14:39:22 +0000
994@@ -1,17 +1,22 @@
995 <?xml version="1.0"?>
996 <openerp>
997- <data>
998+ <data noupdate="1">
999
1000- <!-- Create a portal member attached to a partner -->
1001+ <!-- Create a partner, that is also a portal user -->
1002+ <record id="partner_demo_portal" model="res.partner">
1003+ <field name="name">Demo Portal User</field>
1004+ <field name="email">demo@portal.example.com</field>
1005+ <field name="supplier" eval="False"/>
1006+ <field name="customer" eval="True"/>
1007+ </record>
1008 <record id="demo_user0" model="res.users">
1009- <field name="name">Demo Portal User</field>
1010+ <field name="partner_id" ref="partner_demo_portal"/>
1011 <field name="login">portal</field>
1012 <field name="password">portal</field>
1013+ <field name="signature">--
1014+Mr Demo Portal</field>
1015 <!-- Avoid auto-including this user in any default group -->
1016 <field name="groups_id" eval="[(5,)]"/>
1017- <field name="supplier" eval="False"/>
1018- <field name="customer" eval="True"/>
1019- <field name="email">demo@portal.wrong.address</field>
1020 </record>
1021
1022 <!-- Add the demo user to the portal (and therefore to the portal member group) -->
1023@@ -24,33 +29,41 @@
1024 <field name="subject">Our company's first blog-post !</field>
1025 <field name="model">mail.group</field>
1026 <field name="res_id" ref="company_news_feed"/>
1027- <field name="body"><![CDATA[Hello, and welcome to our company's portal !
1028-
1029-Lorem ipsum <b>sit amet</b>, consectetur <em>adipiscing elit</em>. Pellentesque et quam sapien, in sagittis tellus.
1030-Praesent 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.
1031-
1032-Fusce 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.
1033-
1034-Nulla turpis leo, rhoncus ut egestas sit amet, consectetur vitae urna. Mauris in dolor in sapien tempus vehicula.]]></field>
1035+ <field name="body"><![CDATA[<p>Hello, and welcome to our company's portal !</p>
1036+<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>
1037+<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>
1038 <field name="type">comment</field>
1039+ <field name="subtype_id" ref="mail.mt_comment"/>
1040 <field name="author_id" ref="base.partner_root"/>
1041 </record>
1042
1043 <record id="message_company_news0_comment0" model="mail.message">
1044 <field name="model">mail.group</field>
1045 <field name="res_id" ref="company_news_feed"/>
1046- <field name="body"><![CDATA[Great first blogpost ! (first comment)]]></field>
1047- <field name="parent_id" ref="message_company_news0"/>
1048- <field name="type">comment</field>
1049+ <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>
1050+ <field name="parent_id" ref="message_company_news0"/>
1051+ <field name="type">comment</field>
1052+ <field name="subtype_id" ref="mail.mt_comment"/>
1053+ <field name="author_id" ref="partner_demo_portal"/>
1054+ </record>
1055+
1056+ <record id="message_company_news0_comment1" model="mail.message">
1057+ <field name="model">mail.group</field>
1058+ <field name="res_id" ref="company_news_feed"/>
1059+ <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>
1060+ <field name="parent_id" ref="message_company_news0"/>
1061+ <field name="type">comment</field>
1062+ <field name="subtype_id" ref="mail.mt_comment"/>
1063 <field name="author_id" ref="base.res_partner_1"/>
1064 </record>
1065
1066- <record id="message_company_news0_comment1" model="mail.message">
1067+ <record id="message_company_news0_comment2" model="mail.message">
1068 <field name="model">mail.group</field>
1069 <field name="res_id" ref="company_news_feed"/>
1070- <field name="body"><![CDATA[Thanks ! (second comment)]]></field>
1071+ <field name="body"><![CDATA[<p>This feature is realy great! We will be able to communicate directly to our partners!</p>]]></field>
1072 <field name="parent_id" ref="message_company_news0"/>
1073 <field name="type">comment</field>
1074+ <field name="subtype_id" ref="mail.mt_comment"/>
1075 <field name="author_id" ref="base.partner_demo"/>
1076 </record>
1077
1078
1079=== modified file 'portal/tests/test_portal.py'
1080--- portal/tests/test_portal.py 2012-10-09 15:54:56 +0000
1081+++ portal/tests/test_portal.py 2012-11-14 14:39:22 +0000
1082@@ -19,12 +19,11 @@
1083 #
1084 ##############################################################################
1085
1086-from openerp.addons.mail.tests import test_mail
1087-from openerp.tools import append_content_to_html
1088+from openerp.addons.mail.tests import test_mail_mockup
1089 from osv.orm import except_orm
1090
1091
1092-class test_portal(test_mail.TestMailMockups):
1093+class test_portal(test_mail_mockup.TestMailMockups):
1094
1095 def setUp(self):
1096 super(test_portal, self).setUp()
1097
1098=== modified file 'portal/wizard/portal_wizard.py'
1099--- portal/wizard/portal_wizard.py 2012-10-25 13:09:30 +0000
1100+++ portal/wizard/portal_wizard.py 2012-11-14 14:39:22 +0000
1101@@ -24,10 +24,9 @@
1102
1103 from osv import osv, fields
1104 from tools.translate import _
1105-from tools.misc import email_re
1106+from tools import email_re
1107 from openerp import SUPERUSER_ID
1108
1109-from base.res.res_partner import _lang_get
1110 _logger = logging.getLogger(__name__)
1111
1112 # welcome email sent to portal users
1113
1114=== modified file 'project/project_data.xml'
1115--- project/project_data.xml 2012-11-02 15:41:54 +0000
1116+++ project/project_data.xml 2012-11-14 14:39:22 +0000
1117@@ -125,11 +125,11 @@
1118 <field name="model">mail.group</field>
1119 <field name="res_id" ref="mail.group_all_employees"/>
1120 <field name="type">notification</field>
1121+ <field name="subtype_id" ref="mail.mt_comment"/>
1122 <field name="subject">Project Management application installed!</field>
1123- <field name="body">Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.
1124-
1125-You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology.
1126-You can also manage issues/bugs in projects by installing the "Issue Tracker" application.</field>
1127+ <field name="body"><![CDATA[<p>Manage multi-level projects and tasks. You can delegate tasks, track task work, and review your planning.</p>
1128+<p>You can manage todo lists on tasks by installing the "Todo Lists" application, supporting the Getting Things Done (GTD) methodology.</p>
1129+<p>You can also manage issues/bugs in projects by installing the "Issue Tracker" application.</p>]]></field>
1130 </record>
1131 </data>
1132 </openerp>
1133
1134=== modified file 'project_gtd/project_gtd_data.xml'
1135--- project_gtd/project_gtd_data.xml 2012-08-30 14:18:52 +0000
1136+++ project_gtd/project_gtd_data.xml 2012-11-14 14:39:22 +0000
1137@@ -30,9 +30,10 @@
1138 <field name="model">mail.group</field>
1139 <field name="res_id" ref="mail.group_all_employees"/>
1140 <field name="type">notification</field>
1141+ <field name="subtype_id" ref="mail.mt_comment"/>
1142 <field name="subject">Todo Lists application installed!</field>
1143- <field name="body">Add todo items on project tasks, to help you organize your work.
1144-This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.</field>
1145+ <field name="body"><![CDATA[<p>Add todo items on project tasks, to help you organize your work.
1146+This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.</p>]]></field>
1147 </record>
1148
1149 </data>
1150
1151=== modified file 'project_issue/project_issue_data.xml'
1152--- project_issue/project_issue_data.xml 2012-11-02 15:41:54 +0000
1153+++ project_issue/project_issue_data.xml 2012-11-14 14:39:22 +0000
1154@@ -36,10 +36,11 @@
1155 <field name="model">mail.group</field>
1156 <field name="res_id" ref="mail.group_all_employees"/>
1157 <field name="type">notification</field>
1158+ <field name="subtype_id" ref="mail.mt_comment"/>
1159 <field name="subject">Issue Tracker application installed!</field>
1160- <field name="body">Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
1161+ <field name="body"><![CDATA[<p>Manage the issues you might face in a project, such as bugs in a system, client complaints or material breakdowns.
1162 You can record issues, assign them to a responsible person, and keep track of their status as they evolve over time.
1163-Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</field>
1164+Access all issues from the top Project menu, and access the issues of a specific project via the projects gallery view.</p>]]></field>
1165 </record>
1166
1167 <!-- Mail subtypes -->
1168
1169=== modified file 'purchase/purchase_data.xml'
1170--- purchase/purchase_data.xml 2012-10-02 20:40:23 +0000
1171+++ purchase/purchase_data.xml 2012-11-14 14:39:22 +0000
1172@@ -7,10 +7,10 @@
1173 <field name="model">mail.group</field>
1174 <field name="res_id" ref="mail.group_all_employees"/>
1175 <field name="type">notification</field>
1176+ <field name="subtype_id" ref="mail.mt_comment"/>
1177 <field name="subject">Purchase Management application installed!</field>
1178- <field name="body">From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.
1179-
1180-You can also manage purchase requisitions, see also the Purchase Settings.</field>
1181+ <field name="body"><![CDATA[<p>From the top menu Purchases, create purchase orders to buy products from your suppliers, enter supplier invoices and manage payments.</p>
1182+<p>You can also manage purchase requisitions, see also the Purchase Settings.</p>]]></field>
1183 </record>
1184
1185 <record id="req_link_purchase_order" model="res.request.link">
1186
1187=== modified file 'sale/sale_data.xml'
1188--- sale/sale_data.xml 2012-10-02 20:40:23 +0000
1189+++ sale/sale_data.xml 2012-11-14 14:39:22 +0000
1190@@ -38,10 +38,10 @@
1191 <field name="model">mail.group</field>
1192 <field name="res_id" ref="mail.group_all_employees"/>
1193 <field name="type">notification</field>
1194+ <field name="subtype_id" ref="mail.mt_comment"/>
1195 <field name="subject">Sales Management application installed!</field>
1196- <field name="body">This application lets you create and send quotations and process your sales orders; from delivery to invoicing.
1197-
1198-If you need to manage your sales pipeline (leads, opportunities, phonecalls), the &lt;i&gt;CRM&lt;/i&gt; application may be useful. Use the Settings menu to install it.</field>
1199+ <field name="body"><![CDATA[<p>This application lets you create and send quotations and process your sales orders; from delivery to invoicing.</p>
1200+<p>If you need to manage your sales pipeline (leads, opportunities, phonecalls), the &lt;i&gt;CRM&lt;/i&gt; application may be useful. Use the Settings menu to install it.</p>]]></field>
1201 </record>
1202 </data>
1203 </openerp>
1204
1205=== modified file 'stock/stock_data.xml'
1206--- stock/stock_data.xml 2012-10-02 20:40:23 +0000
1207+++ stock/stock_data.xml 2012-11-14 14:39:22 +0000
1208@@ -6,9 +6,10 @@
1209 <field name="model">mail.group</field>
1210 <field name="res_id" ref="mail.group_all_employees"/>
1211 <field name="type">notification</field>
1212+ <field name="subtype_id" ref="mail.mt_comment"/>
1213 <field name="subject">Warehouse Management application installed!</field>
1214- <field name="body">Manage your product inventoy and stock locations: you can control stock moves history and planning,
1215-watch your stock valuation, and track production lots upstream and downstream (based on serial numbers).</field>
1216+ <field name="body"><![CDATA[<p>Manage your product inventoy and stock locations: you can control stock moves history and planning,
1217+watch your stock valuation, and track production lots upstream and downstream (based on serial numbers).</p>]]></field>
1218 </record>
1219
1220 <record id="stock_journal_sequence" model="ir.sequence">

Subscribers

People subscribed via source and target branches

to all changes: