Files
odoo_source/addons/mail/models/mail_group.py
T
Valerie Pirenne c24332e6da [IMP][ADD] mail, various: timeline view.
This commit introduces a new view type, the timeline view. This view is
intended to display messages like the previous chatter. This is now a view
like the form or list view. Like other views it will be possible to have
custom templates for some specific needs, allowing customization.

[IMP] mail: the value tracking is modified. Previously messages were created
containing the modified values. Those values are now stored, using a new
model mail.tracking.value. The message body is dynamically build based on
the values. Tests have been updated.

This version is temporary. Indeed two main modifications will come in a short
future :

 - the new design will improve the display
 - the slack mode will change the way the Inbox and notifications are managed

All glory to the Hypnotoad.

Special thanks to Valerie Pirenne (vpi), Jerome Maes (jem) and Richat Mathot
(rim) that did not code but said a lot of things. Martin Trigaux (mat) did
nothing, a bit like for the slides modules, but he is busy sending emails.
2015-05-21 12:10:25 +02:00

198 lines
9.2 KiB
Python

# -*- coding: utf-8 -*-
from openerp import _, api, fields, models, modules, tools
from openerp.exceptions import UserError
class MailGroup(models.Model):
""" A mail_group is a collection of users sharing messages in a discussion
group. The group mechanics are based on the followers. """
_description = 'Discussion group'
_name = 'mail.group'
_mail_flat_thread = False
_mail_post_access = 'read'
_inherit = ['mail.thread']
_inherits = {'mail.alias': 'alias_id'}
def _get_default_image(self):
image_path = modules.get_module_resource('mail', 'static/src/img', 'groupdefault.png')
return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
name = fields.Char('Name', required=True, translate=True)
description = fields.Text('Description')
menu_id = fields.Many2one('ir.ui.menu', string='Related Menu', required=True, ondelete="cascade")
public = fields.Selection([
('public', 'Everyone'),
('private', 'Invited people only'),
('groups', 'Selected group of users')],
'Privacy', required=True, default='groups',
help='This group is visible by non members. Invisible groups can add members through the invite button.')
group_public_id = fields.Many2one('res.groups', string='Authorized Group',
default=lambda self: self.env.ref('base.group_user'))
group_ids = fields.Many2many(
'res.groups', rel='mail_group_res_group_rel',
id1='mail_group_id', id2='groups_id', string='Auto Subscription',
help="Members of those groups will automatically added as followers. "
"Note that they will be able to manage their subscription manually "
"if necessary.")
# image: all image fields are base64 encoded and PIL-supported
image = fields.Binary("Photo", default=_get_default_image,
help="This field holds the image used as photo for the group, limited to 1024x1024px.")
image_medium = fields.Binary('Medium-sized photo', compute='_get_image', inverse='_set_image', store=True,
help="Medium-sized photo of the group. It is automatically "
"resized as a 128x128px image, with aspect ratio preserved. "
"Use this field in form views or some kanban views.")
image_small = fields.Binary('Small-sized photo', compute='_get_image', inverse='_set_image', store=True,
help="Small-sized photo of the group. It is automatically "
"resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required.")
alias_id = fields.Many2one(
'mail.alias', 'Alias', ondelete="restrict", required=True,
help="The email address associated with this group. New emails received will automatically "
"create new topics.")
@api.one
@api.depends('image')
def _get_image(self):
res = tools.image_get_resized_images(self.image)
self.image_medium = res['image_medium']
self.image_small = res['image_small']
def _set_image(self):
self.image = tools.image_resize_image_big(self.image)
@api.model
def create(self, vals):
# get parent menu
menu_parent = self.env.ref('mail.mail_group_root')
# Create menu id
menu = self.env['ir.ui.menu'].sudo().create({'name': vals['name'], 'parent_id': menu_parent.id})
vals['menu_id'] = menu.id
# Create group and alias
group = super(MailGroup, self.with_context(
alias_model_name=self._name, alias_parent_model_name=self._name, mail_create_nolog=True)
).create(vals)
group.alias_id.write({"alias_force_thread_id": group.id, 'alias_parent_thread_id': group.id})
# Create action window for this group and link the menu to it
inbox_ref = self.env.ref('mail.action_mail_group_feeds')
search_ref = self.env.ref('mail.view_message_search')
act_domain = [('model', '=', 'mail.group'), ('res_id', '=', group.id)]
act_context = {'default_model': 'mail.group',
'default_res_id': group.id,
'options': {'view_mailbox': False,
'view_inbox': True,
'read_action': 'read',
'compose_placeholder': 'Send a message to the group'},
'params': {'header_description': group._get_header(),
'name': vals['name'],}
}
act_res_model = 'mail.message'
act_search_view_id = search_ref.id
new_action = inbox_ref.sudo().copy(default={'domain': act_domain,
'context': act_context,
'res_model': act_res_model,
'search_view_id': act_search_view_id,
'name': vals['name']})
menu.write({'action': 'ir.actions.act_window,%d' % new_action.id, 'mail_group_id': group.id})
if vals.get('group_ids'):
group._subscribe_users()
return group
@api.multi
def unlink(self):
aliases = self.mapped('alias_id')
menus = self.mapped('menu_id')
# Delete mail_group
try:
all_emp_group = self.env.ref('mail.group_all_employees')
except ValueError:
all_emp_group = None
if all_emp_group and all_emp_group in self:
raise UserError(_('You cannot delete those groups, as the Whole Company group is required by other modules.'))
res = super(MailGroup, self).unlink()
# Cascade-delete mail aliases as well, as they should not exist without the mail group.
aliases.sudo().unlink()
# Cascade-delete menu entries as well
menus.sudo().unlink()
return res
@api.multi
def write(self, vals):
result = super(MailGroup, self).write(vals)
if vals.get('group_ids'):
self._subscribe_users()
# if description, name or alias is changed: update action window
if vals.get('description') or vals.get('name') or vals.get('alias_id') or vals.get('alias_name'):
for group in self:
if (vals.get('name')):
group.menu_id.action.sudo().write({'name': vals.get('name')})
# if name is changed: update menu
if vals.get('name'):
self.sudo().mapped('menu_id').write({'name': vals.get('name')})
return result
def _get_header(self):
self.ensure_one()
header = '%(description)s%(gateway)s' % {
'description': '%s<br />' % self.description if self.description else '',
'gateway': _('Group email gateway: %s@%s') % (self.alias_name, self.alias_domain) if self.alias_name and self.alias_domain else ''
}
return header
# compat
_generate_header_description = _get_header
def _subscribe_users(self):
for mail_group in self:
partner_ids = mail_group.mapped('group_ids').mapped('users').mapped('partner_id')
mail_group.message_subscribe(partner_ids.ids)
@api.multi
def action_follow(self):
""" Wrapper because message_subscribe_users take a user_ids=None
that receive the context without the wrapper. """
return self.message_subscribe_users()
@api.multi
def action_unfollow(self):
""" Wrapper because message_unsubscribe_users take a user_ids=None
that receive the context without the wrapper. """
return self.message_unsubscribe_users()
@api.model
def get_suggested_thread(self, removed_suggested_threads=None):
"""Show the suggestion of groups if display_groups_suggestions if the
user perference allows it."""
if not self.env.user.display_groups_suggestions:
return []
return super(MailGroup, self).get_suggested_thread(removed_suggested_threads)
@api.multi
def message_get_email_values(self, notif_mail=None):
self.ensure_one()
res = super(MailGroup, self).message_get_email_values(notif_mail=notif_mail)
headers = {}
if res.get('headers'):
try:
headers.update(eval(res['headers']))
except Exception:
pass
headers['Precedence'] = 'list'
# avoid out-of-office replies from MS Exchange
# http://blogs.technet.com/b/exchange/archive/2006/10/06/3395024.aspx
headers['X-Auto-Response-Suppress'] = 'OOF'
if self.alias_domain and self.alias_name:
headers['List-Id'] = '%s.%s' % (self.alias_name, self.alias_domain)
headers['List-Post'] = '<mailto:%s@%s>' % (self.alias_name, self.alias_domain)
# Avoid users thinking it was a personal message
# X-Forge-To: will replace To: after SMTP envelope is determined by ir.mail.server
list_to = '"%s" <%s@%s>' % (self.name, self.alias_name, self.alias_domain)
headers['X-Forge-To'] = list_to
res['headers'] = repr(headers)
return res