diff options
| author | Raphael Collet <rco@openerp.com> | 2014-07-06 16:44:26 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2014-07-06 17:05:41 +0200 |
| commit | cbe2dbb672a6c55d86f2e515f9d1cdfee426ef80 (patch) | |
| tree | d6ff62b719fce32392397783c961b734b1e4c50e /addons/mail | |
| parent | d78192c489d3be66cd6487b39f5ce7ba4733a187 (diff) | |
[MERGE] new v8 api by rco
A squashed merge is required as the conversion of the apiculture branch from
bzr to git was not correctly done. The git history contains irrelevant blobs
and commits. This branch brings a lot of changes and fixes, too many to list
exhaustively.
- New orm api, objects are now used instead of ids
- Environements to encapsulates cr uid context while maintaining backward compatibility
- Field compute attribute is a new object oriented way to define function fields
- Shared browse record cache
- New onchange protocol
- Optional copy flag on fields
- Documentation update
- Dead code cleanup
- Lots of fixes
Diffstat (limited to 'addons/mail')
| -rw-r--r-- | addons/mail/mail_followers.py | 31 | ||||
| -rw-r--r-- | addons/mail/mail_group.py | 11 | ||||
| -rw-r--r-- | addons/mail/mail_group_menu.py | 2 | ||||
| -rw-r--r-- | addons/mail/mail_mail.py | 13 | ||||
| -rw-r--r-- | addons/mail/mail_message.py | 45 | ||||
| -rw-r--r-- | addons/mail/mail_thread.py | 32 | ||||
| -rw-r--r-- | addons/mail/res_users.py | 2 | ||||
| -rw-r--r-- | addons/mail/static/scripts/__init__.py | 22 | ||||
| -rwxr-xr-x | addons/mail/static/scripts/openerp_mailgate.py | 8 | ||||
| -rw-r--r-- | addons/mail/static/scripts/openerp_mailgate/__init__.py | 22 | ||||
| -rw-r--r-- | addons/mail/static/src/js/mail_followers.js | 4 | ||||
| -rw-r--r-- | addons/mail/tests/common.py | 30 | ||||
| -rw-r--r-- | addons/mail/tests/test_mail_features.py | 14 | ||||
| -rw-r--r-- | addons/mail/tests/test_mail_gateway.py | 12 | ||||
| -rw-r--r-- | addons/mail/tests/test_mail_group.py | 2 | ||||
| -rw-r--r-- | addons/mail/tests/test_mail_message.py | 61 | ||||
| -rw-r--r-- | addons/mail/tests/test_message_read.py | 2 | ||||
| -rw-r--r-- | addons/mail/update.py | 2 | ||||
| -rw-r--r-- | addons/mail/wizard/mail_compose_message.py | 3 |
19 files changed, 141 insertions, 177 deletions
diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index 2045353b0e5..42238e75553 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -48,6 +48,25 @@ class mail_followers(osv.Model): help="Message subtypes followed, meaning subtypes that will be pushed onto the user's Wall."), } + # + # Modifying followers change access rights to individual documents. As the + # cache may contain accessible/inaccessible data, one has to refresh it. + # + def create(self, cr, uid, vals, context=None): + res = super(mail_followers, self).create(cr, uid, vals, context=context) + self.invalidate_cache(cr, uid, context=context) + return res + + def write(self, cr, uid, ids, vals, context=None): + res = super(mail_followers, self).write(cr, uid, ids, vals, context=context) + self.invalidate_cache(cr, uid, context=context) + return res + + def unlink(self, cr, uid, ids, context=None): + res = super(mail_followers, self).unlink(cr, uid, ids, context=context) + self.invalidate_cache(cr, uid, context=context) + return res + class mail_notification(osv.Model): """ Class holding notifications pushed to partners. Followers and partners @@ -60,7 +79,7 @@ class mail_notification(osv.Model): _columns = { 'partner_id': fields.many2one('res.partner', string='Contact', ondelete='cascade', required=True, select=1), - 'read': fields.boolean('Read', select=1), + 'is_read': fields.boolean('Read', select=1), 'starred': fields.boolean('Starred', select=1, help='Starred message that goes into the todo mailbox'), 'message_id': fields.many2one('mail.message', string='Message', @@ -68,14 +87,14 @@ class mail_notification(osv.Model): } _defaults = { - 'read': False, + 'is_read': False, 'starred': False, } def init(self, cr): cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_notification_partner_id_read_starred_message_id',)) if not cr.fetchone(): - cr.execute('CREATE INDEX mail_notification_partner_id_read_starred_message_id ON mail_notification (partner_id, read, starred, message_id)') + cr.execute('CREATE INDEX mail_notification_partner_id_read_starred_message_id ON mail_notification (partner_id, is_read, starred, message_id)') def get_partners_to_email(self, cr, uid, ids, message, context=None): """ Return the list of partners to notify, based on their preferences. @@ -86,7 +105,7 @@ class mail_notification(osv.Model): """ notify_pids = [] for notification in self.browse(cr, uid, ids, context=context): - if notification.read: + if notification.is_read: continue partner = notification.partner_id # Do not send to partners without email address defined @@ -148,12 +167,12 @@ class mail_notification(osv.Model): existing_pids.add(notification.partner_id.id) # update existing notifications - self.write(cr, uid, ids, {'read': False}, context=context) + self.write(cr, uid, ids, {'is_read': False}, context=context) # create new notifications new_pids = set(partner_ids) - existing_pids for new_pid in new_pids: - new_notif_ids.append(self.create(cr, uid, {'message_id': message_id, 'partner_id': new_pid, 'read': False}, context=context)) + new_notif_ids.append(self.create(cr, uid, {'message_id': message_id, 'partner_id': new_pid, 'is_read': False}, context=context)) return new_notif_ids def _notify_email(self, cr, uid, ids, message_id, force_send=False, user_signature=True, context=None): diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 9881e6422c6..eaca5c1182e 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -37,7 +37,7 @@ class mail_group(osv.Model): _inherits = {'mail.alias': 'alias_id'} def _get_image(self, cr, uid, ids, name, args, context=None): - result = dict.fromkeys(ids, False) + result = {} for obj in self.browse(cr, uid, ids, context=context): result[obj.id] = tools.image_get_resized_images(obj.image) return result @@ -163,15 +163,14 @@ class mail_group(osv.Model): def unlink(self, cr, uid, ids, context=None): groups = self.browse(cr, uid, ids, context=context) - # Cascade-delete mail aliases as well, as they should not exist without the mail group. - mail_alias = self.pool.get('mail.alias') alias_ids = [group.alias_id.id for group in groups if group.alias_id] + menu_ids = [group.menu_id.id for group in groups if group.menu_id] # Delete mail_group res = super(mail_group, self).unlink(cr, uid, ids, context=context) - # Delete alias - mail_alias.unlink(cr, SUPERUSER_ID, alias_ids, context=context) + # Cascade-delete mail aliases as well, as they should not exist without the mail group. + self.pool.get('mail.alias').unlink(cr, SUPERUSER_ID, alias_ids, context=context) # Cascade-delete menu entries as well - self.pool.get('ir.ui.menu').unlink(cr, SUPERUSER_ID, [group.menu_id.id for group in groups if group.menu_id], context=context) + self.pool.get('ir.ui.menu').unlink(cr, SUPERUSER_ID, menu_ids, context=context) return res def write(self, cr, uid, ids, vals, context=None): diff --git a/addons/mail/mail_group_menu.py b/addons/mail/mail_group_menu.py index 56d4b5dd564..3e849e62ac5 100644 --- a/addons/mail/mail_group_menu.py +++ b/addons/mail/mail_group_menu.py @@ -42,7 +42,7 @@ class ir_ui_menu(osv.osv): following. Access are done using SUPERUSER_ID to avoid access rights issues for an internal back-end algorithm. """ ids = super(ir_ui_menu, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=False) - partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + partner_id = self.pool.get('res.users').read(cr, uid, [uid], ['partner_id'], context=context)[0]['partner_id'][0] follower_obj = self.pool.get('mail.followers') for menu in self.browse(cr, uid, ids, context=context): if menu.mail_group_id: diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py index 0a6a250bcaa..aeea2c0b1a5 100644 --- a/addons/mail/mail_mail.py +++ b/addons/mail/mail_mail.py @@ -24,7 +24,7 @@ import logging import re from urlparse import urljoin -from openerp import tools +from openerp import api, tools from openerp import SUPERUSER_ID from openerp.addons.base.ir.ir_mail_server import MailDeliveryException from openerp.osv import fields, osv @@ -51,7 +51,7 @@ class mail_mail(osv.Model): ('received', 'Received'), ('exception', 'Delivery Failed'), ('cancel', 'Cancelled'), - ], 'Status', readonly=True), + ], 'Status', readonly=True, copy=False), 'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"), 'references': fields.text('References', help='Message references, such as identifiers of previous messages', readonly=1), @@ -59,7 +59,7 @@ class mail_mail(osv.Model): 'recipient_ids': fields.many2many('res.partner', string='To (Partners)'), 'email_cc': fields.char('Cc', help='Carbon copy message recipients'), 'body_html': fields.text('Rich-text Contents', help="Rich-text/HTML message"), - 'headers': fields.text('Headers'), + 'headers': fields.text('Headers', copy=False), # Auto-detected based on create() - if 'mail_message_id' was passed then this mail is a notification # and during unlink() we will not cascade delete the parent and its attachments 'notification': fields.boolean('Is Notification', @@ -98,6 +98,7 @@ class mail_mail(osv.Model): def cancel(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'cancel'}, context=context) + @api.cr_uid def process_email_queue(self, cr, uid, ids=None, context=None): """Send immediately queued messages, committing after each message is sent - this is not transactional and should @@ -226,8 +227,7 @@ class mail_mail(osv.Model): email sending process has failed :return: True """ - if context is None: - context = {} + context = dict(context or {}) ir_mail_server = self.pool.get('ir.mail_server') ir_attachment = self.pool['ir.attachment'] for mail in self.browse(cr, SUPERUSER_ID, ids, context=context): @@ -301,8 +301,9 @@ class mail_mail(osv.Model): # /!\ can't use mail.state here, as mail.refresh() will cause an error # see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1 + if mail_sent: + _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id) self._postprocess_sent_message(cr, uid, mail, context=context, mail_sent=mail_sent) - _logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id) except MemoryError: # prevent catching transient MemoryErrors, bubble up to notify user or abort cron job # instead of marking the mail as failed diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 42aaef80703..d11495289f7 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -24,7 +24,7 @@ import logging from openerp import tools from email.header import decode_header -from openerp import SUPERUSER_ID +from openerp import SUPERUSER_ID, api from openerp.osv import osv, orm, fields from openerp.tools import html_email_clean from openerp.tools.translate import _ @@ -88,7 +88,7 @@ class mail_message(osv.Model): notif_ids = notif_obj.search(cr, uid, [ ('partner_id', 'in', [partner_id]), ('message_id', 'in', ids), - ('read', '=', False), + ('is_read', '=', False), ], context=context) for notif in notif_obj.browse(cr, uid, notif_ids, context=context): res[notif.message_id.id] = True @@ -96,8 +96,8 @@ class mail_message(osv.Model): def _search_to_read(self, cr, uid, obj, name, domain, context=None): """ Search for messages to read by the current user. Condition is - inversed because we search unread message on a read column. """ - return ['&', ('notification_ids.partner_id.user_ids', 'in', [uid]), ('notification_ids.read', '=', not domain[0][2])] + inversed because we search unread message on a is_read column. """ + return ['&', ('notification_ids.partner_id.user_ids', 'in', [uid]), ('notification_ids.is_read', '=', not domain[0][2])] def _get_starred(self, cr, uid, ids, name, arg, context=None): """ Compute if the message is unread by the current user. """ @@ -114,8 +114,7 @@ class mail_message(osv.Model): return res def _search_starred(self, cr, uid, obj, name, domain, context=None): - """ Search for messages to read by the current user. Condition is - inversed because we search unread message on a read column. """ + """ Search for starred messages by the current user.""" return ['&', ('notification_ids.partner_id.user_ids', 'in', [uid]), ('notification_ids.starred', '=', domain[0][2])] _columns = { @@ -153,7 +152,7 @@ class mail_message(osv.Model): help='Technical field holding the message notifications. Use notified_partner_ids to access notified partners.'), 'subject': fields.char('Subject'), 'date': fields.datetime('Date'), - 'message_id': fields.char('Message-Id', help='Message unique identifier', select=1, readonly=1), + 'message_id': fields.char('Message-Id', help='Message unique identifier', select=1, readonly=1, copy=False), 'body': fields.html('Contents', help='Automatically sanitized HTML contents'), 'to_read': fields.function(_get_to_read, fnct_search=_search_to_read, type='boolean', string='To read', @@ -213,8 +212,9 @@ class mail_message(osv.Model): def download_attachment(self, cr, uid, id_message, attachment_id, context=None): """ Return the content of linked attachments. """ - message = self.browse(cr, uid, id_message, context=context) - if attachment_id in [attachment.id for attachment in message.attachment_ids]: + # this will fail if you cannot read the message + message_values = self.read(cr, uid, [id_message], ['attachment_ids'], context=context)[0] + if attachment_id in message_values['attachment_ids']: attachment = self.pool.get('ir.attachment').browse(cr, SUPERUSER_ID, attachment_id, context=context) if attachment.datas and attachment.datas_fname: return { @@ -227,6 +227,7 @@ class mail_message(osv.Model): # Notification API #------------------------------------------------------ + @api.cr_uid_ids_context def set_message_read(self, cr, uid, msg_ids, read, create_missing=True, context=None): """ Set messages as (un)read. Technically, the notifications related to uid are set to (un)read. If for some msg_ids there are missing @@ -243,22 +244,23 @@ class mail_message(osv.Model): user_pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] if not create_missing: - domain += [('read', '=', not read)] + domain += [('is_read', '=', not read)] notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)read if len(notif_ids) == len(msg_ids) or not create_missing: - notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + notification_obj.write(cr, uid, notif_ids, {'is_read': read}, context=context) return len(notif_ids) # some messages do not have notifications: find which one, create notification, update read status notified_msg_ids = [notification.message_id.id for notification in notification_obj.browse(cr, uid, notif_ids, context=context)] to_create_msg_ids = list(set(msg_ids) - set(notified_msg_ids)) for msg_id in to_create_msg_ids: - notification_obj.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context) - notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) + notification_obj.create(cr, uid, {'partner_id': user_pid, 'is_read': read, 'message_id': msg_id}, context=context) + notification_obj.write(cr, uid, notif_ids, {'is_read': read}, context=context) return len(notif_ids) + @api.cr_uid_ids_context def set_message_starred(self, cr, uid, msg_ids, starred, create_missing=True, context=None): """ Set messages as (un)starred. Technically, the notifications related to uid are set to (un)starred. @@ -276,7 +278,7 @@ class mail_message(osv.Model): 'starred': starred } if starred: - values['read'] = False + values['is_read'] = False notif_ids = notification_obj.search(cr, uid, domain, context=context) @@ -502,6 +504,7 @@ class mail_message(osv.Model): return True + @api.cr_uid_context def message_read(self, cr, uid, ids=None, domain=None, message_unload_ids=None, thread_level=0, context=None, parent_id=False, limit=None): """ Read messages from mail.message, and get back a list of structured @@ -671,7 +674,7 @@ class mail_message(osv.Model): - uid has write or create access on the related document if model, res_id - otherwise: raise """ - def _generate_model_record_ids(msg_val, msg_ids=[]): + def _generate_model_record_ids(msg_val, msg_ids): """ :param model_record_ids: {'model': {'res_id': (msg_id, msg_id)}, ... } :param message_values: {'msg_id': {'model': .., 'res_id': .., 'author_id': ..}} """ @@ -782,8 +785,7 @@ class mail_message(osv.Model): return message_id def create(self, cr, uid, values, context=None): - if context is None: - context = {} + context = dict(context or {}) default_starred = context.pop('default_starred', False) if 'email_from' not in values: # needed to compute reply_to @@ -830,13 +832,6 @@ class mail_message(osv.Model): self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context) return super(mail_message, self).unlink(cr, uid, ids, context=context) - def copy(self, cr, uid, id, default=None, context=None): - """ Overridden to avoid duplicating fields that are unique to each email """ - if default is None: - default = {} - default.update(message_id=False, headers=False) - return super(mail_message, self).copy(cr, uid, id, default=default, context=context) - #------------------------------------------------------ # Messaging API #------------------------------------------------------ @@ -888,5 +883,5 @@ class mail_message(osv.Model): notification_obj.create(cr, uid, { 'message_id': message.parent_id.id, 'partner_id': partner.id, - 'read': True, + 'is_read': True, }, context=context) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 54f2b8d8f8b..ca040597240 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -39,11 +39,11 @@ import re from email.message import Message from urllib import urlencode -from openerp import tools +from openerp import api, tools from openerp import SUPERUSER_ID from openerp.addons.mail.mail_message import decode from openerp.osv import fields, osv, orm -from openerp.osv.orm import browse_record, browse_null +from openerp.osv.orm import BaseModel from openerp.tools.safe_eval import safe_eval as eval from openerp.tools.translate import _ @@ -154,12 +154,12 @@ class mail_thread(osv.AbstractModel): - message_unread: has uid unread message for the document - message_summary: html snippet summarizing the Chatter for kanban views """ res = dict((id, dict(message_unread=False, message_unread_count=0, message_summary=' ')) for id in ids) - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + user_pid = self.pool.get('res.users').read(cr, uid, [uid], ['partner_id'], context=context)[0]['partner_id'][0] # search for unread messages, directly in SQL to improve performances cr.execute(""" SELECT m.res_id FROM mail_message m RIGHT JOIN mail_notification n - ON (n.message_id = m.id AND n.partner_id = %s AND (n.read = False or n.read IS NULL)) + ON (n.message_id = m.id AND n.partner_id = %s AND (n.is_read = False or n.is_read IS NULL)) WHERE m.model = %s AND m.res_id in %s""", (user_pid, self._name, tuple(ids),)) for result in cr.fetchall(): @@ -192,7 +192,7 @@ class mail_thread(osv.AbstractModel): available, which are followed if any """ res = dict((id, dict(message_subtype_data='')) for id in ids) if user_pid is None: - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + user_pid = self.pool.get('res.users').read(cr, uid, [uid], ['partner_id'], context=context)[0]['partner_id'][0] # find current model subtypes, add them to a dictionary subtype_obj = self.pool.get('mail.message.subtype') @@ -232,7 +232,7 @@ class mail_thread(osv.AbstractModel): fol_obj = self.pool.get('mail.followers') fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids)]) res = dict((id, dict(message_follower_ids=[], message_is_follower=False)) for id in ids) - user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + user_pid = self.pool.get('res.users').read(cr, uid, [uid], ['partner_id'], context=context)[0]['partner_id'][0] for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids): res[fol.res_id]['message_follower_ids'].append(fol.partner_id.id) if fol.partner_id.id == user_pid: @@ -448,10 +448,6 @@ class mail_thread(osv.AbstractModel): def copy_data(self, cr, uid, id, default=None, context=None): # avoid tracking multiple temporary changes during copy context = dict(context or {}, mail_notrack=True) - - default = default or {} - default['message_ids'] = [] - default['message_follower_ids'] = [] return super(mail_thread, self).copy_data(cr, uid, id, default=default, context=context) #------------------------------------------------------ @@ -621,7 +617,7 @@ class mail_thread(osv.AbstractModel): # default action is the Inbox action self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) act_model, act_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, *self._get_inbox_action_xml_id(cr, uid, context=context)) - action = self.pool.get(act_model).read(cr, uid, act_id, []) + action = self.pool.get(act_model).read(cr, uid, [act_id], [])[0] params = context.get('params') msg_id = model = res_id = None @@ -1059,11 +1055,12 @@ class mail_thread(osv.AbstractModel): def message_route_process(self, cr, uid, message, message_dict, routes, context=None): # postpone setting message_dict.partner_ids after message_post, to avoid double notifications + context = dict(context or {}) partner_ids = message_dict.pop('partner_ids', []) thread_id = False for model, thread_id, custom_values, user_id, alias in routes: if self._name == 'mail.thread': - context.update({'thread_model': model}) + context['thread_model'] = model if model: model_pool = self.pool[model] if not (thread_id and hasattr(model_pool, 'message_update') or hasattr(model_pool, 'message_new')): @@ -1508,6 +1505,7 @@ class mail_thread(osv.AbstractModel): m2m_attachment_ids.append((0, 0, data_attach)) return m2m_attachment_ids + @api.cr_uid_ids_context def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, content_subtype='html', **kwargs): @@ -1807,10 +1805,8 @@ class mail_thread(osv.AbstractModel): record = self.browse(cr, uid, ids[0], context=context) for updated_field in updated_fields: field_value = getattr(record, updated_field) - if isinstance(field_value, browse_record): + if isinstance(field_value, BaseModel): field_value = field_value.id - elif isinstance(field_value, browse_null): - field_value = False values[updated_field] = field_value # find followers of headers, update structure for new followers @@ -1870,11 +1866,12 @@ class mail_thread(osv.AbstractModel): partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id cr.execute(''' UPDATE mail_notification SET - read=false + is_read=false WHERE message_id IN (SELECT id from mail_message where res_id=any(%s) and model=%s limit 1) and partner_id = %s ''', (ids, self._name, partner_id)) + self.pool.get('mail.notification').invalidate_cache(cr, uid, ['is_read'], context=context) return True def message_mark_as_read(self, cr, uid, ids, context=None): @@ -1882,11 +1879,12 @@ class mail_thread(osv.AbstractModel): partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id cr.execute(''' UPDATE mail_notification SET - read=true + is_read=true WHERE message_id IN (SELECT id FROM mail_message WHERE res_id=ANY(%s) AND model=%s) AND partner_id = %s ''', (ids, self._name, partner_id)) + self.pool.get('mail.notification').invalidate_cache(cr, uid, ['is_read'], context=context) return True #------------------------------------------------------ diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py index e218ea85927..a4b4e68942b 100644 --- a/addons/mail/res_users.py +++ b/addons/mail/res_users.py @@ -39,7 +39,7 @@ class res_users(osv.Model): _columns = { 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="restrict", required=True, help="Email address internally associated with this user. Incoming "\ - "emails will appear in the user's notifications."), + "emails will appear in the user's notifications.", copy=False), 'display_groups_suggestions': fields.boolean("Display Groups Suggestions"), } diff --git a/addons/mail/static/scripts/__init__.py b/addons/mail/static/scripts/__init__.py deleted file mode 100644 index 3b6a8c7e4b0..00000000000 --- a/addons/mail/static/scripts/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2009-2010 OpenERP SA (<http://www.openerp.com>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -import openerp_mailgate
\ No newline at end of file diff --git a/addons/mail/static/scripts/openerp_mailgate.py b/addons/mail/static/scripts/openerp_mailgate.py index 99ebc8f770b..e3dbdf4adc0 100755 --- a/addons/mail/static/scripts/openerp_mailgate.py +++ b/addons/mail/static/scripts/openerp_mailgate.py @@ -30,10 +30,10 @@ import optparse import sys import xmlrpclib import smtplib -from email.MIMEMultipart import MIMEMultipart -from email.MIMEBase import MIMEBase -from email.MIMEText import MIMEText -from email.Utils import COMMASPACE, formatdate +from email.mime.multipart import MIMEMultipart +from email.mime.base import MIMEBase +from email.mime.text import MIMEText +from email.utils import COMMASPACE, formatdate from email import Encoders class DefaultConfig(object): diff --git a/addons/mail/static/scripts/openerp_mailgate/__init__.py b/addons/mail/static/scripts/openerp_mailgate/__init__.py deleted file mode 100644 index de2e2bf390d..00000000000 --- a/addons/mail/static/scripts/openerp_mailgate/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2009-2010 OpenERP SA (<http://www.openerp.com>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -import openerp_mailgate diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index bf83fe6d7c6..bd84dac714d 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -172,8 +172,8 @@ openerp_mail_followers = function(session, mail) { fetch_generic: function (error, event) { var self = this; event.preventDefault(); - return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) { - var pid = results['partner_id'][0]; + return this.ds_users.call('read', [[this.session.uid], ['partner_id']]).then(function (results) { + var pid = results[0]['partner_id'][0]; self.message_is_follower = (_.indexOf(self.value, pid) != -1); }).then(self.proxy('display_generic')); }, diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index d53a8078c96..5a5c28f95d7 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -24,30 +24,28 @@ from openerp.tests import common class TestMail(common.TransactionCase): - def _mock_smtp_gateway(self, *args, **kwargs): - return args[2]['Message-Id'] - def _init_mock_build_email(self): self._build_email_args_list = [] self._build_email_kwargs_list = [] - def _mock_build_email(self, *args, **kwargs): - """ Mock build_email to be able to test its values. Store them into - some internal variable for latter processing. """ - self._build_email_args_list.append(args) - self._build_email_kwargs_list.append(kwargs) - return self._build_email(*args, **kwargs) - def setUp(self): super(TestMail, self).setUp() cr, uid = self.cr, self.uid # Install mock SMTP gateway + test = self + + def build_email(self, *args, **kwargs): + test._build_email_args_list.append(args) + test._build_email_kwargs_list.append(kwargs) + return build_email.origin(self, *args, **kwargs) + + def send_email(self, cr, uid, message, *args, **kwargs): + return message['Message-Id'] + self._init_mock_build_email() - self._build_email = self.registry('ir.mail_server').build_email - self.registry('ir.mail_server').build_email = self._mock_build_email - self._send_email = self.registry('ir.mail_server').send_email - self.registry('ir.mail_server').send_email = self._mock_smtp_gateway + self.registry('ir.mail_server')._patch_method('build_email', build_email) + self.registry('ir.mail_server')._patch_method('send_email', send_email) # Usefull models self.ir_model = self.registry('ir.model') @@ -129,6 +127,6 @@ class TestMail(common.TransactionCase): def tearDown(self): # Remove mocks - self.registry('ir.mail_server').build_email = self._build_email - self.registry('ir.mail_server').send_email = self._send_email + self.registry('ir.mail_server')._revert_method('build_email') + self.registry('ir.mail_server')._revert_method('send_email') super(TestMail, self).tearDown() diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index 2bf7bb91264..fdd87bbcfab 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -280,7 +280,7 @@ class test_mail(TestMail): self.assertNotIn('res_id=%s' % group_pigs.id, url, 'notification email: link based on message should not contain res_id') - @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') def test_12_inbox_redirection(self): """ Tests designed to test the inbox redirection of emails notification URLs. """ cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs @@ -654,7 +654,7 @@ class test_mail(TestMail): { 'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])] }, context={ - 'default_composition_mode': 'reply', + 'default_composition_mode': 'comment', 'default_res_id': self.group_pigs_id, 'default_parent_id': message.id }) @@ -772,14 +772,13 @@ class test_mail(TestMail): def test_30_needaction(self): """ Tests for mail.message needaction. """ cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs - group_pigs_demo = self.mail_group.browse(cr, self.user_raoul_id, self.group_pigs_id) na_admin_base = self.mail_message._needaction_count(cr, uid, domain=[]) na_demo_base = self.mail_message._needaction_count(cr, user_raoul.id, domain=[]) # Test: number of unread notification = needaction on mail.message notif_ids = self.mail_notification.search(cr, uid, [ ('partner_id', '=', user_admin.partner_id.id), - ('read', '=', False) + ('is_read', '=', False) ]) na_count = self.mail_message._needaction_count(cr, uid, domain=[]) self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count') @@ -787,13 +786,14 @@ class test_mail(TestMail): # Do: post 2 message on group_pigs as admin, 3 messages as demo user for dummy in range(2): group_pigs.message_post(body='My Body', subtype='mt_comment') + raoul_pigs = group_pigs.sudo(user_raoul) for dummy in range(3): - group_pigs_demo.message_post(body='My Demo Body', subtype='mt_comment') + raoul_pigs.message_post(body='My Demo Body', subtype='mt_comment') # Test: admin has 3 new notifications (from demo), and 3 new needaction notif_ids = self.mail_notification.search(cr, uid, [ ('partner_id', '=', user_admin.partner_id.id), - ('read', '=', False) + ('is_read', '=', False) ]) self.assertEqual(len(notif_ids), na_admin_base + 3, 'Admin should have 3 new unread notifications') na_admin = self.mail_message._needaction_count(cr, uid, domain=[]) @@ -803,7 +803,7 @@ class test_mail(TestMail): # Test: demo has 0 new notifications (not a follower, not receiving its own messages), and 0 new needaction notif_ids = self.mail_notification.search(cr, uid, [ ('partner_id', '=', user_raoul.partner_id.id), - ('read', '=', False) + ('is_read', '=', False) ]) self.assertEqual(len(notif_ids), na_demo_base + 0, 'Demo should have 0 new unread notifications') na_demo = self.mail_message._needaction_count(cr, user_raoul.id, domain=[]) diff --git a/addons/mail/tests/test_mail_gateway.py b/addons/mail/tests/test_mail_gateway.py index 3fbf3d40405..1b16f151cdf 100644 --- a/addons/mail/tests/test_mail_gateway.py +++ b/addons/mail/tests/test_mail_gateway.py @@ -164,7 +164,7 @@ class TestMailgateway(TestMail): self.assertIn('<div dir="ltr">Should create a multipart/mixed: from gmail, <b>bold</b>, with attachment.<br clear="all"><div><br></div>', res.get('body', ''), 'message_parse: html version should be in body after parsing multipart/mixed') - @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') def test_10_message_process(self): """ Testing incoming emails processing. """ cr, uid, user_raoul = self.cr, self.uid, self.user_raoul @@ -203,8 +203,8 @@ class TestMailgateway(TestMail): # Test: one group created by mailgateway administrator self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created') frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - res = self.mail_group.perm_read(cr, uid, [frog_group.id], details=False) - self.assertEqual(res[0].get('create_uid'), uid, + res = self.mail_group.get_metadata(cr, uid, [frog_group.id])[0].get('create_uid') or [None] + self.assertEqual(res[0], uid, 'message_process: group should have been created by uid as alias_user__id is False on the alias') # Test: one message that is the incoming email self.assertEqual(len(frog_group.message_ids), 1, @@ -271,8 +271,8 @@ class TestMailgateway(TestMail): # Test: one group created by Raoul self.assertEqual(len(frog_groups), 1, 'message_process: a new mail.group should have been created') frog_group = self.mail_group.browse(cr, uid, frog_groups[0]) - res = self.mail_group.perm_read(cr, uid, [frog_group.id], details=False) - self.assertEqual(res[0].get('create_uid'), self.user_raoul_id, + res = self.mail_group.get_metadata(cr, uid, [frog_group.id])[0].get('create_uid') or [None] + self.assertEqual(res[0], self.user_raoul_id, 'message_process: group should have been created by alias_user_id') # Test: one message that is the incoming email self.assertEqual(len(frog_group.message_ids), 1, @@ -536,7 +536,7 @@ class TestMailgateway(TestMail): self.assertIn('<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>', msg.body, 'message_process: plaintext incoming email incorrectly parsed') - @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm') + @mute_logger('openerp.addons.mail.mail_thread', 'openerp.models') def test_20_thread_parent_resolution(self): """ Testing parent/child relationships are correctly established when processing incoming mails """ cr, uid = self.cr, self.uid diff --git a/addons/mail/tests/test_mail_group.py b/addons/mail/tests/test_mail_group.py index 34c7f0c00e0..c131ce0bd0b 100644 --- a/addons/mail/tests/test_mail_group.py +++ b/addons/mail/tests/test_mail_group.py @@ -27,7 +27,7 @@ from openerp.tools import mute_logger class TestMailGroup(TestMail): - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm') + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') def test_00_mail_group_access_rights(self): """ Testing mail_group access rights and basic mail_thread features """ cr, uid, user_noone_id, user_employee_id = self.cr, self.uid, self.user_noone_id, self.user_employee_id diff --git a/addons/mail/tests/test_mail_message.py b/addons/mail/tests/test_mail_message.py index d4a7ae75df3..40d6786e2c9 100644 --- a/addons/mail/tests/test_mail_message.py +++ b/addons/mail/tests/test_mail_message.py @@ -161,7 +161,7 @@ class TestMailMessage(TestMail): self.assertEqual(mail.reply_to, 'someone@example.com', 'mail_mail: reply_to should equal the rpely_to given to create') - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm') + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') def test_10_mail_message_search_access_rights(self): """ Testing mail_message.search() using specific _search implementation """ cr, uid, group_pigs_id = self.cr, self.uid, self.group_pigs_id @@ -196,7 +196,7 @@ class TestMailMessage(TestMail): msg_ids = self.mail_message.search(cr, uid, [('subject', 'like', '_Test')]) self.assertEqual(set([msg_id1, msg_id2, msg_id3, msg_id4, msg_id5, msg_id6, msg_id7, msg_id8]), set(msg_ids), 'mail_message search failed') - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm') + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') def test_15_mail_message_check_access_rule(self): """ Testing mail_message.check_access_rule() """ cr, uid = self.cr, self.uid @@ -218,8 +218,8 @@ class TestMailMessage(TestMail): message_id = self.mail_message.create(cr, uid, {'body': 'My Body', 'attachment_ids': [(4, attachment_id)]}) # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - self.assertRaises(except_orm, self.mail_message.read, - cr, user_bert_id, message_id) + with self.assertRaises(except_orm): + self.mail_message.read(cr, user_bert_id, message_id) # Do: message is pushed to Bert notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id}) # Test: Bert reads the message, ok because notification pushed @@ -229,11 +229,11 @@ class TestMailMessage(TestMail): # Do: remove notification self.mail_notification.unlink(cr, uid, notif_id) # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - self.assertRaises(except_orm, self.mail_message.read, - cr, self.user_bert_id, message_id) + with self.assertRaises(except_orm): + self.mail_message.read(cr, self.user_bert_id, message_id) # Test: Bert downloads attachment, crash because he can't read message - self.assertRaises(except_orm, self.mail_message.download_attachment, - cr, user_bert_id, message_id, attachment_id) + with self.assertRaises(except_orm): + self.mail_message.download_attachment(cr, user_bert_id, message_id, attachment_id) # Do: Bert is now the author self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id}) # Test: Bert reads the message, ok because Bert is the author @@ -241,8 +241,8 @@ class TestMailMessage(TestMail): # Do: Bert is not the author anymore self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id}) # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - self.assertRaises(except_orm, self.mail_message.read, - cr, user_bert_id, message_id) + with self.assertRaises(except_orm): + self.mail_message.read(cr, user_bert_id, message_id) # Do: message is attached to a document Bert can read, Jobs self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id}) # Test: Bert reads the message, ok because linked to a doc he is allowed to read @@ -250,33 +250,33 @@ class TestMailMessage(TestMail): # Do: message is attached to a document Bert cannot read, Pigs self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id}) # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc - self.assertRaises(except_orm, self.mail_message.read, - cr, user_bert_id, message_id) + with self.assertRaises(except_orm): + self.mail_message.read(cr, user_bert_id, message_id) # ---------------------------------------- # CASE2: create # ---------------------------------------- # Do: Bert creates a message on Pigs -> ko, no creation rights - self.assertRaises(AccessError, self.mail_message.create, - cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_pigs_id, 'body': 'Test'}) + with self.assertRaises(AccessError): + self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_pigs_id, 'body': 'Test'}) # Do: Bert create a message on Jobs -> ko, no creation rights - self.assertRaises(AccessError, self.mail_message.create, - cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'}) + with self.assertRaises(AccessError): + self.mail_message.create(cr, user_bert_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'}) # Do: Bert create a private message -> ko, no creation rights - self.assertRaises(AccessError, self.mail_message.create, - cr, user_bert_id, {'body': 'Test'}) + with self.assertRaises(AccessError): + self.mail_message.create(cr, user_bert_id, {'body': 'Test'}) # Do: Raoul creates a message on Jobs -> ok, write access to the related document self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_jobs_id, 'body': 'Test'}) # Do: Raoul creates a message on Priv -> ko, no write access to the related document - self.assertRaises(except_orm, self.mail_message.create, - cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test'}) + with self.assertRaises(except_orm): + self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test'}) # Do: Raoul creates a private message -> ok self.mail_message.create(cr, user_raoul_id, {'body': 'Test'}) # Do: Raoul creates a reply to a message on Priv -> ko - self.assertRaises(except_orm, self.mail_message.create, - cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id}) + with self.assertRaises(except_orm): + self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id}) # Do: Raoul creates a reply to a message on Priv-> ok if has received parent self.mail_notification.create(cr, uid, {'message_id': priv_msg_id, 'partner_id': self.partner_raoul_id}) self.mail_message.create(cr, user_raoul_id, {'model': 'mail.group', 'res_id': self.group_priv_id, 'body': 'Test', 'parent_id': priv_msg_id}) @@ -335,7 +335,7 @@ class TestMailMessage(TestMail): self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created') # Test: notification read notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif.read, 'mail_notification read failed') + self.assertTrue(notif['is_read'], 'mail_notification read failed') self.assertFalse(msg.to_read, 'mail_message read failed') # Do: Raoul reads msg @@ -346,7 +346,7 @@ class TestMailMessage(TestMail): self.assertEqual(len(notif_ids), 1, 'mail_message set_message_read: more than one notification created') # Test: notification read notif = self.mail_notification.browse(cr, uid, notif_ids[0]) - self.assertTrue(notif.read, 'mail_notification starred failed') + self.assertTrue(notif['is_read'], 'mail_notification starred failed') self.assertFalse(msg_raoul.to_read, 'mail_message starred failed') # Do: Admin unreads msg @@ -383,7 +383,7 @@ class TestMailMessage(TestMail): self.assertEqual(set(msg.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter') self.assertEqual(set(msg_raoul.vote_user_ids), set([self.user_raoul]), 'mail_message vote: after unvoting, Bert should be in the voter') - @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm') + @mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models') def test_50_mail_flow_access_rights(self): """ Test a Chatter-looks alike flow to test access rights """ cr, uid = self.cr, self.uid @@ -400,9 +400,9 @@ class TestMailMessage(TestMail): # ---------------------------------------- # Do: Bert reads Jobs basic fields, ok because public = read access on the group - self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) + self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['name', 'description']) # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages - jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] + jobs_message_ids = self.mail_group.read(cr, user_bert_id, [self.group_jobs_id], ['message_ids'])[0]['message_ids'] self.mail_message.read(cr, user_bert_id, jobs_message_ids) # Do: Bert browses Jobs, ok (no direct browse of partners), ok for messages, ko for followers (accessible to employees or partner manager) bert_jobs = self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) @@ -413,9 +413,8 @@ class TestMailMessage(TestMail): with self.assertRaises(AccessError): trigger_read = partner.name # Do: Bert comments Jobs, ko because no creation right - self.assertRaises(AccessError, - self.mail_group.message_post, - cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + with self.assertRaises(AccessError): + self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') # Do: Bert writes on its own profile, ko because no message create access with self.assertRaises(AccessError): @@ -444,5 +443,5 @@ class TestMailMessage(TestMail): # Do: Raoul replies to a Jobs message using the composer compose_id = mail_compose.create(cr, user_raoul_id, {'subject': 'Subject', 'body': 'Body text'}, - {'default_composition_mode': 'reply', 'default_parent_id': pigs_msg_id}) + {'default_composition_mode': 'comment', 'default_parent_id': pigs_msg_id}) mail_compose.send_mail(cr, user_raoul_id, [compose_id]) diff --git a/addons/mail/tests/test_message_read.py b/addons/mail/tests/test_message_read.py index c02e9a32278..fbf30f2ed22 100644 --- a/addons/mail/tests/test_message_read.py +++ b/addons/mail/tests/test_message_read.py @@ -46,7 +46,7 @@ class test_mail_access_rights(TestMail): ordered_msg_ids = [msg_id2, msg_id4, msg_id6, msg_id8, msg_id10, msg_id1, msg_id3, msg_id5, msg_id7, msg_id9, msg_id0] # Test: raoul received notifications - raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('is_read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) self.assertEqual(len(raoul_notification_ids), 11, 'message_post: wrong number of produced notifications') # Test: read some specific ids diff --git a/addons/mail/update.py b/addons/mail/update.py index d2873f3a5bf..a76c54ff2da 100644 --- a/addons/mail/update.py +++ b/addons/mail/update.py @@ -59,7 +59,7 @@ def get_sys_logs(self, cr, uid): add_arg = {"timeout":30} if sys.version_info >= (2,6) else {} arguments = {'arg0': msg, "action": "update",} - arguments_raw = werkzeug.url_encode(arguments) + arguments_raw = werkzeug.urls.url_encode(arguments) url = config.get("publisher_warranty_url") diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 0425cd1ee0e..41dc4a9b438 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -196,8 +196,7 @@ class mail_compose_message(osv.TransientModel): def send_mail(self, cr, uid, ids, context=None): """ Process the wizard content and proceed with sending the related email(s), rendering any template patterns on the fly if needed. """ - if context is None: - context = {} + context = dict(context or {}) # clean the context (hint: mass mailing sets some default values that # could be wrongly interpreted by mail_mail) |
