from lxml import etree
import logging
import pytz
+import re
import socket
import time
import xmlrpclib
-import re
from email.message import Message
+from email.utils import formataddr
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 _
- 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():
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')
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:
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)
#------------------------------------------------------
# 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
if params:
msg_id = params.get('message_id')
model = params.get('model')
- res_id = params.get('res_id')
+ res_id = params.get('res_id', params.get('id')) # signup automatically generated id instead of res_id
if not msg_id and not (model and res_id):
return action
if msg_id and not (model and res_id):
if model_obj.check_access_rights(cr, uid, 'read', raise_exception=False):
try:
model_obj.check_access_rule(cr, uid, [res_id], 'read', context=context)
- action = model_obj.get_formview_action(cr, uid, res_id, context=context)
+ action = model_obj.get_access_action(cr, uid, res_id, context=context)
except (osv.except_osv, orm.except_orm):
pass
action.update({
res[record.id] = {'partner_ids': list(recipient_ids), 'email_to': email_to, 'email_cc': email_cc}
return res
- def message_get_reply_to(self, cr, uid, ids, context=None):
+ def message_get_reply_to(self, cr, uid, ids, default=None, context=None):
""" Returns the preferred reply-to email address that is basically
the alias of the document, if it exists. """
- if not self._inherits.get('mail.alias'):
- return [False for id in ids]
- return ["%s@%s" % (record.alias_name, record.alias_domain)
- if record.alias_domain and record.alias_name else False
- for record in self.browse(cr, SUPERUSER_ID, ids, context=context)]
+ if context is None:
+ context = {}
+ model_name = context.get('thread_model') or self._name
+ alias_domain = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.catchall.domain", context=context)
+ res = dict.fromkeys(ids, False)
+
+ # alias domain: check for aliases and catchall
+ aliases = {}
+ doc_names = {}
+ if alias_domain:
+ if model_name and model_name != 'mail.thread':
+ alias_ids = self.pool['mail.alias'].search(
+ cr, SUPERUSER_ID, [
+ ('alias_parent_model_id.model', '=', model_name),
+ ('alias_parent_thread_id', 'in', ids),
+ ('alias_name', '!=', False)
+ ], context=context)
+ aliases.update(
+ dict((alias.alias_parent_thread_id, '%s@%s' % (alias.alias_name, alias_domain))
+ for alias in self.pool['mail.alias'].browse(cr, SUPERUSER_ID, alias_ids, context=context)))
+ doc_names.update(
+ dict((ng_res[0], ng_res[1])
+ for ng_res in self.pool[model_name].name_get(cr, SUPERUSER_ID, aliases.keys(), context=context)))
+ # left ids: use catchall
+ left_ids = set(ids).difference(set(aliases.keys()))
+ if left_ids:
+ catchall_alias = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.catchall.alias", context=context)
+ if catchall_alias:
+ aliases.update(dict((res_id, '%s@%s' % (catchall_alias, alias_domain)) for res_id in left_ids))
+ # compute name of reply-to
+ company_name = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).company_id.name
+ for res_id in aliases.keys():
+ email_name = '%s%s' % (company_name, doc_names.get(res_id) and (' ' + doc_names[res_id]) or '')
+ email_addr = aliases[res_id]
+ res[res_id] = formataddr((email_name, email_addr))
+ left_ids = set(ids).difference(set(aliases.keys()))
+ if left_ids and default:
+ res.update(dict((res_id, default) for res_id in left_ids))
+ return res
def message_get_email_values(self, cr, uid, id, notif_mail=None, context=None):
- """ Temporary method to create custom notification email values for a given
- model and document. This should be better to have a headers field on
- the mail.mail model, computed when creating the notification email, but
- this cannot be done in a stable version.
-
- TDE FIXME: rethink this ulgy thing. """
+ """ Get specific notification email values to store on the notification
+ mail_mail. Void method, inherit it to add custom values. """
res = dict()
return res
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')):
# Note specific
#------------------------------------------------------
- def log(self, cr, uid, id, message, secondary=False, context=None):
- _logger.warning("log() is deprecated. As this module inherit from "\
- "mail.thread, the message will be managed by this "\
- "module instead of by the res.log mechanism. Please "\
- "use mail_thread.message_post() instead of the "\
- "now deprecated res.log.")
- self.message_post(cr, uid, [id], message, context=context)
-
def _message_add_suggested_recipient(self, cr, uid, result, obj, partner=None, email=None, reason='', context=None):
""" Called by message_get_suggested_recipients, to add a suggested
recipient in the result dictionary. The form is :
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):
# set in the context.
model = False
if thread_id:
- model = context.get('thread_model', self._name) if self._name == 'mail.thread' else self._name
- if model != self._name and hasattr(self.pool[model], 'message_post'):
+ model = context.get('thread_model', False) if self._name == 'mail.thread' else self._name
+ if model and model != self._name and hasattr(self.pool[model], 'message_post'):
del context['thread_model']
return self.pool[model].message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, content_subtype=content_subtype, **kwargs)
self.message_subscribe(cr, uid, [thread_id], list(partner_to_subscribe), context=context)
# _mail_flat_thread: automatically set free messages to the first posted message
- if self._mail_flat_thread and not parent_id and thread_id:
+ if self._mail_flat_thread and model and not parent_id and thread_id:
message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1)
parent_id = message_ids and message_ids[0] or False
# we want to set a parent: force to set the parent_id to the oldest ancestor, to avoid having more than 1 level of thread
values.update({
'author_id': author_id,
'model': model,
- 'res_id': thread_id or False,
+ 'res_id': model and thread_id or False,
'body': body,
'subject': subject or False,
'type': type,
# done with SUPERUSER_ID, because on some models users can post only with read access, not necessarily write access
self.write(cr, SUPERUSER_ID, [thread_id], {'message_last_post': fields.datetime.now()}, context=context)
message = mail_message.browse(cr, uid, msg_id, context=context)
- if message.author_id and thread_id and type != 'notification' and not context.get('mail_create_nosubscribe'):
+ if message.author_id and model and thread_id and type != 'notification' and not context.get('mail_create_nosubscribe'):
self.message_subscribe(cr, uid, [thread_id], [message.author_id.id], context=context)
return msg_id
if user_ids is None:
user_ids = [uid]
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
- return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context)
+ result = self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context)
+ if partner_ids and result:
+ self.pool['ir.ui.menu'].clear_cache()
+ return result
def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
""" Add partners to the records followers. """
if user_ids is None:
user_ids = [uid]
partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)]
- return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
+ result = self.message_unsubscribe(cr, uid, ids, partner_ids, context=context)
+ if partner_ids and result:
+ self.pool['ir.ui.menu'].clear_cache()
+ return result
def message_unsubscribe(self, cr, uid, ids, partner_ids, context=None):
""" Remove partners from the records followers. """
], context=context)
return fol_obj.unlink(cr, SUPERUSER_ID, fol_ids, context=context)
- def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None):
+ def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=None, context=None):
""" Returns the list of relational fields linking to res.users that should
trigger an auto subscribe. The default list checks for the fields
- called 'user_id'
Override this method if a custom behavior is needed about fields
that automatically subscribe users.
"""
+ if auto_follow_fields is None:
+ auto_follow_fields = ['user_id']
user_field_lst = []
for name, column_info in self._all_columns.items():
if name in auto_follow_fields and name in updated_fields and getattr(column_info.column, 'track_visibility', False) and column_info.column._obj == 'res.users':
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
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):
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
#------------------------------------------------------