Thibault Delavallée (OpenERP) has proposed merging
lp:~openerp-dev/openobject-addons/trunk-openchatter-3-5-tde into
lp:openobject-addons.
Requested reviews:
OpenERP Core Team (openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-openchatter-3-5-tde/+merge/117577
OpenChatter 3.5: share / portal
===============================
Purpose
- Share/Invite flow cleaning and integration with chatter
- Add attachments to chatter
--
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-openchatter-3-5-tde/+merge/117577
Your team OpenERP R&D Team is subscribed to branch
lp:~openerp-dev/openobject-addons/trunk-openchatter-3-5-tde.
=== modified file 'mail/data/mail_group_data.xml'
--- mail/data/mail_group_data.xml 2012-07-29 15:16:11 +0000
+++ mail/data/mail_group_data.xml 2012-08-01 08:03:19 +0000
@@ -21,7 +21,7 @@
<value>Welcome to OpenERP!</value>
<value>Your homepage is a summary of messages you received and key information about documents you follow.
-The top menu bar contains all applications you installed. You can use this <i>Settings</i> menu to intall more applications, activate others features or give access to new users.
+The top menu bar contains all applications you installed. You can use this <i>Settings</i> menu to install more applications, activate others features or give access to new users.
To setup your preferences (name, email signature, avatar), click on the top right corner.</value>
</function>
=== modified file 'mail/mail_message.py'
--- mail/mail_message.py 2012-07-20 12:57:29 +0000
+++ mail/mail_message.py 2012-08-01 08:03:19 +0000
@@ -93,6 +93,9 @@
return result
def name_get(self, cr, uid, ids, context=None):
+ # name_get may received int id instead of an id list
+ if isinstance(ids, (int, long)):
+ ids = [ids]
res = []
for message in self.browse(cr, uid, ids, context=context):
name = ''
=== modified file 'mail/mail_thread.py'
--- mail/mail_thread.py 2012-07-25 09:44:50 +0000
+++ mail/mail_thread.py 2012-08-01 08:03:19 +0000
@@ -140,81 +140,57 @@
# mail.message wrappers and tools
#------------------------------------------------------
- def message_create(self, cr, uid, thread_id, vals, context=None):
+ def message_create(self, cr, uid, thread_record, vals, context=None):
""" OpenChatter: wrapper of mail.message create method
- creates the mail.message
- - automatically subscribe the message writer
+ - automatically subscribe the writer to the thread if any
- push the message to subscribed users
+ - send emails to subscribed users that should receive an email
+ confirmation
+
+ :param thread_record: a browse_record object on the thread to which
+ the new message will be attached. It set to None, the message
+ is not attached to any thread.
+ :param vals: dictionary of values for the message to be created that
+ will be given to the mail.message create method.
"""
- if context is None:
- context = {}
-
+ # protection against calls with id or ids instead of browse records
+ if isinstance(thread_record, (int, long)):
+ thread_record = self.pool.get(self._name).browse(cr, uid, thread_record, context=context)
+ elif isinstance(thread_record, (list)):
+ if all(isinstance(thread_id, (int, long)) for thread_id in thread_record):
+ thread_record = self.pool.get(self._name).browse(cr, uid, thread_record[0], context=context)
+ else:
+ thread_record = thread_record[0]
+
message_obj = self.pool.get('mail.message')
notification_obj = self.pool.get('mail.notification')
body = vals.get('body_html', '') if vals.get('content_subtype') == 'html' else vals.get('body_text', '')
- # automatically subscribe the writer of the message
- if vals['user_id']:
- self.message_subscribe(cr, uid, [thread_id], [vals['user_id']], context=context)
-
+ # message attached to a thread: subscribe the writer if any, set as
+ # unread if the writer is not the document responsible
+ if thread_record:
+ if vals['user_id']:
+ self.message_subscribe(cr, uid, [thread_record.id], [vals['user_id']], context=context)
+ self.message_create_set_unread(cr, uid, [thread_record.id], context=context)
+
# create message
msg_id = message_obj.create(cr, uid, vals, context=context)
-
- # Set as unread if writer is not the document responsible
- self.message_create_set_unread(cr, uid, [thread_id], context=context)
-
+
# special: if install mode, do not push demo data
- if context.get('install_mode', False):
+ if context and context.get('install_mode'):
return msg_id
-
+ message = message_obj.browse(cr, uid, msg_id, context=context)
+
# get users that will get a notification pushed
- user_to_push_ids = self.message_get_user_ids_to_notify(cr, uid, [thread_id], vals, context=context)
+ user_to_push_ids = self.message_notification_get_user_ids(cr, uid, thread_record, message, context=context)
for id in user_to_push_ids:
notification_obj.create(cr, uid, {'user_id': id, 'message_id': msg_id}, context=context)
# create the email to send
- email_id = self.message_create_notify_by_email(cr, uid, vals, user_to_push_ids, context=context)
+ email_id = self.message_notification_send_email(cr, uid, thread_record, message, user_to_push_ids, context=context)
return msg_id
-
- def message_get_user_ids_to_notify(self, cr, uid, thread_ids, new_msg_vals, context=None):
- subscription_obj = self.pool.get('mail.subscription')
- # get body
- body = new_msg_vals.get('body_html', '') if new_msg_vals.get('content_subtype') == 'html' else new_msg_vals.get('body_text', '')
-
- # get subscribers
- notif_user_ids = self.message_get_subscribers(cr, uid, thread_ids, context=context)
-
- # add users requested via parsing message (@login)
- notif_user_ids += self.message_parse_users(cr, uid, body, context=context)
-
- # add users requested to perform an action (need_action mechanism)
- if hasattr(self, 'get_needaction_user_ids'):
- user_ids_dict = self.get_needaction_user_ids(cr, uid, thread_ids, context=context)
- for id, user_ids in user_ids_dict.iteritems():
- notif_user_ids += user_ids
-
- # add users notified of the parent messages (because: if parent message contains @login, login must receive the replies)
- if new_msg_vals.get('parent_id'):
- notif_obj = self.pool.get('mail.notification')
- parent_notif_ids = notif_obj.search(cr, uid, [('message_id', '=', new_msg_vals.get('parent_id'))], context=context)
- parent_notifs = notif_obj.read(cr, uid, parent_notif_ids, context=context)
- notif_user_ids += [parent_notif['user_id'][0] for parent_notif in parent_notifs]
-
- # remove duplicate entries
- notif_user_ids = list(set(notif_user_ids))
- return notif_user_ids
-
- def message_parse_users(self, cr, uid, string, context=None):
- """Parse message content
- - if find @login -(^|\s)@((\w|@|\.)*)-: returns the related ids
- this supports login that are emails (such as @[email protected])
- """
- regex = re.compile('(^|\s)@((\w|@|\.)*)')
- login_lst = [item[1] for item in regex.findall(string)]
- if not login_lst: return []
- user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context)
- return user_ids
#------------------------------------------------------
# Generic message api
@@ -361,7 +337,7 @@
'reply_to': reply_to,
'original': original, })
- new_msg_ids.append(self.message_create(cr, uid, thread.id, data, context=context))
+ new_msg_ids.append(self.message_create(cr, uid, thread, data, context=context))
return new_msg_ids
def message_append_dict(self, cr, uid, ids, msg_dict, context=None):
@@ -498,33 +474,36 @@
message_ids = self.message_search(cr, uid, ids, fetch_ancestors, ancestor_ids,
limit, offset, domain, context=context)
messages = self.pool.get('mail.message').read(cr, uid, message_ids, context=context)
-
- """ Retrieve all attachments names """
+ # format attachments for Chatter
+ self.message_read_format_attachments(cr, uid, messages, context=context)
+ # set the threads as read
+ self.message_check_and_set_read(cr, uid, ids, context=context)
+ # sort and return the messages
+ messages = sorted(messages, key=lambda d: (-d['id']))
+ return messages
+
+ def message_read_format_attachments(self, cr, uid, messages, context=None):
+ """ Format attachment of messages to display in Chatter.
+
+ :param messages: list of read results (value dictionaries) on
+ mail.messages records
+ """
+ # use empty string as a placeholder
map_id_to_name = dict((attachment_id, '') for message in messages for attachment_id in message['attachment_ids'])
- map_id_to_name = {}
- for msg in messages:
- for attach_id in msg["attachment_ids"]:
- map_id_to_name[attach_id] = '' # use empty string as a placeholder
- ids = map_id_to_name.keys()
- names = self.pool.get('ir.attachment').name_get(cr, uid, ids, context=context)
+ attachment_ids = map_id_to_name.keys()
+ names = self.pool.get('ir.attachment').name_get(cr, uid, attachment_ids, context=context)
# convert the list of tuples into a dictionnary
for name in names:
map_id_to_name[name[0]] = name[1]
# give corresponding ids and names to each message
- for msg in messages:
- msg["attachments"] = []
-
- for attach_id in msg["attachment_ids"]:
- msg["attachments"].append({'id': attach_id, 'name': map_id_to_name[attach_id]})
-
- # Set the threads as read
- self.message_check_and_set_read(cr, uid, ids, context=context)
- # Sort and return the messages
- messages = sorted(messages, key=lambda d: (-d['id']))
- return messages
+ for message in messages:
+ message["attachments"] = []
+ for attach_id in message["attachment_ids"]:
+ message["attachments"].append({'id': attach_id, 'name': map_id_to_name[attach_id]})
+ return True
def message_get_pushed_messages(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None,
limit=100, offset=0, msg_search_domain=[], context=None):
@@ -557,8 +536,10 @@
# get messages
msg_ids = msg_obj.search(cr, uid, [('id', 'in', msg_ids)], context=context)
if (fetch_ancestors): msg_ids = self._message_search_ancestor_ids(cr, uid, ids, msg_ids, ancestor_ids, context=context)
- msgs = msg_obj.read(cr, uid, msg_ids, context=context)
- return msgs
+ messages = msg_obj.read(cr, uid, msg_ids, context=context)
+ # format attachments for Chatter
+ self.message_read_format_attachments(cr, uid, messages, context=context)
+ return messages
#------------------------------------------------------
# Mail gateway
@@ -905,7 +886,49 @@
# Notification API
#------------------------------------------------------
- def message_create_notify_by_email(self, cr, uid, new_msg_values, user_to_notify_ids, context=None):
+ def message_notification_get_user_ids(self, cr, uid, thread_record, message, context=None):
+ """ OpenChatter tools method. This method returns the user_ids that have
+ receive a mail.notification to push a message to their wall.
+
+ :param thread_record: a browse_record object on the thread to which
+ the new message will be attached. It set to None, the message
+ is not attached to any thread.
+ :param message: a browse record object on the newly created message
+ """
+ subscription_obj = self.pool.get('mail.subscription')
+ # get subscribers
+ notif_user_ids = self.message_get_subscribers(cr, uid, [thread_record.id], context=context)
+ # add users requested via parsing message (@login)
+ body = message.body_html if message.content_subtype == 'html' else message.body_text
+ notif_user_ids += self.message_notification_parse_users(cr, uid, body, context=context)
+ # add users requested to perform an action (need_action mechanism)
+ if hasattr(self, 'get_needaction_user_ids'):
+ user_ids_dict = self.get_needaction_user_ids(cr, uid, [thread_record.id], context=context)
+ for id, user_ids in user_ids_dict.iteritems():
+ notif_user_ids += user_ids
+ # add users notified of the parent messages (because: if parent message contains @login, login must receive the replies)
+ if message.parent_id:
+ notif_obj = self.pool.get('mail.notification')
+ parent_notif_ids = notif_obj.search(cr, uid, [('message_id', '=', message.parent_id.id)], context=context)
+ parent_notifs = notif_obj.read(cr, uid, parent_notif_ids, ['user_id'], context=context)
+ notif_user_ids += [parent_notif['user_id'][0] for parent_notif in parent_notifs]
+
+ # remove duplicate entries
+ notif_user_ids = list(set(notif_user_ids))
+ return notif_user_ids
+
+ def message_notification_parse_users(self, cr, uid, string, context=None):
+ """ Parse message content
+ - if find @login -(^|\s)@((\w|@|\.)*)-: returns the related ids
+ this supports login that are emails (such as @[email protected])
+ """
+ regex = re.compile('(^|\s)@((\w|@|\.)*)')
+ login_lst = [item[1] for item in regex.findall(string)]
+ if not login_lst: return []
+ user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context)
+ return user_ids
+
+ def message_notification_send_email(self, cr, uid, thread_record, message, user_ids, context=None):
""" When creating a new message and pushing notifications, emails
must be send if users have chosen to receive notifications
by email via the notification_email_pref field.
@@ -917,26 +940,27 @@
- never: never receive notifications
Note that an user should never receive notifications for messages
he has created.
-
- :param new_msg_values: dictionary of message values, those that
- are given to the create method
- :param user_to_notify_ids: list of user_ids, user that will
- receive a notification on their Wall
+
+ :param thread_record: a browse_record object on the thread to which
+ the new message will be attached. It set to None, the message
+ is not attached to any thread.
+ :param message: a browse record object on the newly created message
+ :param user_ids: list of user_ids, user that will receive a
+ notification on their Wall
"""
message_obj = self.pool.get('mail.message')
res_users_obj = self.pool.get('res.users')
- body = new_msg_values.get('body_html', '') if new_msg_values.get('content_subtype') == 'html' else new_msg_values.get('body_text', '')
-
+
# remove message writer
- if user_to_notify_ids.count(new_msg_values.get('user_id')) > 0:
- user_to_notify_ids.remove(new_msg_values.get('user_id'))
+ if user_ids.count(message.user_id.id) > 0:
+ user_ids.remove(message.user_id.id)
# get user_ids directly asked
- user_to_push_from_parse_ids = self.message_parse_users(cr, uid, body, context=context)
-
+ body = message.body_html if message.content_subtype == 'html' else message.body_text
+ user_to_push_from_parse_ids = self.message_notification_parse_users(cr, uid, body, context=context)
# try to find an email_to
email_to = ''
- for user in res_users_obj.browse(cr, uid, user_to_notify_ids, context=context):
+ for user in res_users_obj.browse(cr, uid, user_ids, context=context):
if not user.notification_email_pref == 'all' and \
not (user.notification_email_pref == 'to_me' and user.id in user_to_push_from_parse_ids):
continue
@@ -950,38 +974,60 @@
return
# try to find an email_from
- current_user = res_users_obj.browse(cr, uid, [uid], context=context)[0]
- email_from = new_msg_values.get('email_from')
+ user_writer = res_users_obj.browse(cr, uid, [uid], context=context)[0]
+ email_from = message.email_from
if not email_from:
- email_from = current_user.user_email
+ email_from = user_writer.user_email
- # get email content, create it (with mail_message.create)
- email_values = self.message_create_notify_get_email_dict(cr, uid, new_msg_values, email_from, email_to, context)
+ # get email content, create it using directly mail_message.create
+ email_values = self.message_notification_get_email_dict(cr, uid, thread_record, message, user_writer, email_from, email_to, context=context)
email_id = message_obj.create(cr, uid, email_values, context=context)
return email_id
- def message_create_notify_get_email_dict(self, cr, uid, new_msg_values, email_from, email_to, context=None):
- values = dict(new_msg_values)
-
- body_html = new_msg_values.get('body_html', '')
+ def message_notification_get_email_dict(self, cr, uid, thread_record, message, user_writer, email_from, email_to, context=None):
+ """ Create the dictionary of values for the notification email to
+ send.
+
+ :param thread_record: a browse_record object on the thread to which
+ the new message will be attached. It set to None, the message
+ is not attached to any thread.
+ :param user_writer: a browse_record object on the message writer. It
+ will be used to display some data in the footer of the send
+ emails.
+ :param email_from: email_from of the send notification email
+ :param email_to: list of emails that will receive the notification
+ emails, formatted like 'r@r, r@r, r@r'
+ """
+ footer_dict_values = {
+ 'company_name': user_writer.company_id.name,
+ 'record_name': message.record_name,
+ }
+ # update html body
+ body_html = message.body_html
if body_html:
- body_html += '\n\n----------\nThis email was send automatically by OpenERP, because you have subscribed to a document.'
- body_text = new_msg_values.get('body_text', '')
+ body_html += '''
+<div>
+ <p>This email was send automatically by %(company_name)s, because you are subscribed to %(record_name)s.</p>
+</div>''' % footer_dict_values
+ # update text body
+ body_text = message.body_text
if body_text:
- body_text += '\n\n----------\nThis email was send automatically by OpenERP, because you have subscribed to a document.'
- values.update({
+ body_text += '''----------
+This email was send automatically by %(company_name)s, because you are subscribed to %(record_name)s.''' % footer_dict_values
+ # create email values
+ values = {
+ 'subject': 'Notification for %s: %s' % (message.record_name, message.subject),
+ 'body_html': body_html,
+ 'body_text': body_text,
'type': 'email',
'state': 'outgoing',
+ 'content_subtype': message.content_subtype,
'email_from': email_from,
'email_to': email_to,
- 'subject': 'New message',
- 'content_subtype': new_msg_values.get('content_subtype', 'plain'),
- 'body_html': body_html,
- 'body_text': body_text,
'auto_delete': True,
'res_model': '',
'res_id': False,
- })
+ }
return values
def message_remove_pushed_notifications(self, cr, uid, ids, msg_ids, remove_childs=True, context=None):
=== modified file 'mail/res_users.py'
--- mail/res_users.py 2012-07-20 13:29:04 +0000
+++ mail/res_users.py 2012-08-01 08:03:19 +0000
@@ -33,9 +33,8 @@
_columns = {
'notification_email_pref': fields.selection([
- ('all', 'All feeds'),
- ('comments', 'Only comments'),
- ('to_me', 'Only when sent directly to me'),
+ ('all', 'All Feeds'),
+ ('to_me', 'Only send directly to me'),
('none', 'Never')
], 'Receive Feeds by Email', required=True,
help="Choose in which case you want to receive an email when you "\
@@ -64,8 +63,14 @@
self.message_subscribe(cr, uid, [user_id], [user_id], context=context)
# create a welcome message
company_name = user.company_id.name if user.company_id else 'the company'
- message = _('%s has joined %s! Welcome in OpenERP !') % (user.name, company_name)
- self.message_append_note(cr, uid, [user_id], subject='Welcom to OpenERP', body=message, type='comment', context=context)
+ message = '''%s has joined %s! Welcome in OpenERP !
+
+Your homepage is a summary of messages you received and key information about documents you follow.
+
+The top menu bar contains all applications you installed. You can use this <i>Settings</i> menu to install more applications, activate others features or give access to new users.
+
+To setup your preferences (name, email signature, avatar), click on the top right corner.''' % (user.name, company_name)
+ self.message_append_note(cr, uid, [user_id], subject='Welcome to OpenERP', body=message, type='comment', content_subtype='html', context=context)
return user_id
def message_search_get_domain(self, cr, uid, ids, context=None):
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp