[FIX] project,hr: improved alias creation/duplication
[odoo/odoo.git] / addons / mail / mail_group.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2010-today OpenERP SA (<http://www.openerp.com>)
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>
19 #
20 ##############################################################################
21
22 import datetime as DT
23 import openerp
24 import openerp.tools as tools
25 from operator import itemgetter
26 from osv import osv
27 from osv import fields
28 import tools
29 from tools.translate import _
30 from lxml import etree
31
32 class mail_group(osv.osv):
33     """
34     A mail_group is a collection of users sharing messages in a discussion
35     group. Group users are users that follow the mail group, using the
36     subscription/follow mechanism of OpenSocial. A mail group has nothing
37     in common with res.users.group.
38     Additional information on fields:
39         - ``member_ids``: user member of the groups are calculated with
40           ``message_get_subscribers`` method from mail.thread
41         - ``member_count``: calculated with member_ids
42         - ``is_subscriber``: calculated with member_ids
43         
44     """
45     
46     _description = 'Discussion group'
47     _name = 'mail.group'
48     _inherit = ['mail.thread']
49     _inherits = {'mail.alias': 'alias_id'}
50
51     def _get_image(self, cr, uid, ids, name, args, context=None):
52         result = dict.fromkeys(ids, False)
53         for obj in self.browse(cr, uid, ids, context=context):
54             result[obj.id] = tools.image_get_resized_images(obj.image)
55         return result
56     
57     def _set_image(self, cr, uid, id, name, value, args, context=None):
58         return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
59     
60     def get_member_ids(self, cr, uid, ids, field_names, args, context=None):
61         if context is None:
62             context = {}
63         result = dict.fromkeys(ids)
64         for id in ids:
65             result[id] = {}
66             result[id]['member_ids'] = self.message_get_subscribers(cr, uid, [id], context=context)
67             result[id]['member_count'] = len(result[id]['member_ids'])
68             result[id]['is_subscriber'] = uid in result[id]['member_ids']
69         return result
70     
71     def search_member_ids(self, cr, uid, obj, name, args, context=None):
72         if context is None:
73             context = {}
74         sub_obj = self.pool.get('mail.subscription')
75         sub_ids = sub_obj.search(cr, uid, ['&', ('res_model', '=', obj._name), ('user_id', '=', args[0][2])], context=context)
76         subs = sub_obj.read(cr, uid, sub_ids, context=context)
77         return [('id', 'in', map(itemgetter('res_id'), subs))]
78     
79     def get_last_month_msg_nbr(self, cr, uid, ids, name, args, context=None):
80         result = {}
81         message_obj = self.pool.get('mail.message')
82         for id in ids:
83             lower_date = (DT.datetime.now() - DT.timedelta(days=30)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
84             result[id] = self.message_search(cr, uid, [id], limit=None, domain=[('date', '>=', lower_date)], count=True, context=context)
85         return result
86     
87     def _get_default_image(self, cr, uid, context=None):
88         image_path = openerp.modules.get_module_resource('mail', 'static/src/img', 'groupdefault.png')
89         return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
90     
91     _columns = {
92         'name': fields.char('Name', size=64, required=True),
93         'description': fields.text('Description'),
94         'responsible_id': fields.many2one('res.users', string='Responsible',
95             ondelete='set null', required=True, select=1,
96             help="Responsible of the group that has all rights on the record."),
97         'public': fields.boolean('Visible by non members', help='This group is visible by non members. \
98             Invisible groups can add members through the invite button.'),
99         'group_ids': fields.many2many('res.groups', rel='mail_group_res_group_rel',
100             id1='mail_group_id', id2='groups_id', string='Linked groups',
101             help="Members of those groups will automatically added as followers. "\
102                     "Note that they will be able to manage their subscription manually "\
103                     "if necessary."),
104         'image': fields.binary("Photo",
105             help="This field holds the image used as photo for the "\
106                  "user. The image is base64 encoded, and PIL-supported. "\
107                  "It is limited to a 12024x1024 px image."),
108         'image_medium': fields.function(_get_image, fnct_inv=_set_image,
109             string="Medium-sized photo", type="binary", multi="_get_image",
110             store = {
111                 'mail.group': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
112             },
113             help="Medium-sized photo of the group. It is automatically "\
114                  "resized as a 180x180px image, with aspect ratio preserved. "\
115                  "Use this field in form views or some kanban views."),
116         'image_small': fields.function(_get_image, fnct_inv=_set_image,
117             string="Small-sized photo", type="binary", multi="_get_image",
118             store = {
119                 'mail.group': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
120             },
121             help="Small-sized photo of the group. It is automatically "\
122                  "resized as a 50x50px image, with aspect ratio preserved. "\
123                  "Use this field anywhere a small image is required."),
124         'member_ids': fields.function(get_member_ids, fnct_search=search_member_ids,
125             type='many2many', relation='res.users', string='Group members', multi='get_member_ids'),
126         'member_count': fields.function(get_member_ids, type='integer',
127             string='Member count', multi='get_member_ids'),
128         'is_subscriber': fields.function(get_member_ids, type='boolean',
129             string='Joined', multi='get_member_ids'),
130         'last_month_msg_nbr': fields.function(get_last_month_msg_nbr, type='integer',
131             string='Messages count for last month'),
132         'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True, 
133                                     help="The email address associated with this group. New emails received will automatically "
134                                          "create new topics."),
135     }
136
137     _defaults = {
138         'public': True,
139         'responsible_id': (lambda s, cr, uid, ctx: uid),
140         'image': _get_default_image,
141     }
142
143     def _subscribe_user_with_group_m2m_command(self, cr, uid, ids, group_ids_command, context=None):
144         # form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]}
145         user_group_ids = [command[1] for command in group_ids_command if command[0] == 4]
146         user_group_ids += [id for command in group_ids_command if command[0] == 6 for id in command[2]]
147         # retrieve the user member of those groups
148         user_ids = []
149         res_groups_obj = self.pool.get('res.groups')
150         for group in res_groups_obj.browse(cr, uid, user_group_ids, context=context):
151             user_ids += [user.id for user in group.users]
152         # subscribe the users
153         return self.message_subscribe(cr, uid, ids, user_ids, context=context)
154
155     def create(self, cr, uid, vals, context=None):
156         mail_alias = self.pool.get('mail.alias')
157         if not vals.get('alias_id'):
158             vals.pop('alias_name', None) # prevent errors during copy()
159             alias_id = mail_alias.create_unique_alias(cr, uid, 
160                           # Using '+' allows using subaddressing for those who don't
161                           # have a catchall domain setup.
162                           {'alias_name': "group+"+vals['name']},
163                           model_name=self._name, context=context)
164             vals['alias_id'] = alias_id
165         mail_group_id = super(mail_group, self).create(cr, uid, vals, context)
166         mail_alias.write(cr, uid, [vals['alias_id']], {"alias_force_thread_id": mail_group_id}, context)
167        
168         if vals.get('group_ids'):
169             self._subscribe_user_with_group_m2m_command(cr, uid, [mail_group_id], vals.get('group_ids'), context=context)
170
171         return mail_group_id
172
173     def unlink(self, cr, uid, ids, context=None):
174         # Cascade-delete mail aliases as well, as they should not exist without the mail group.
175         mail_alias = self.pool.get('mail.alias')
176         alias_ids = [group.alias_id.id for group in self.browse(cr, uid, ids, context=context) if group.alias_id]
177         res = super(mail_group, self).unlink(cr, uid, ids, context=context)
178         mail_alias.unlink(cr, uid, alias_ids, context=context)
179         return res
180
181     def write(self, cr, uid, ids, vals, context=None):
182         if vals.get('group_ids'):
183             self._subscribe_user_with_group_m2m_command(cr, uid, ids, vals.get('group_ids'), context=context)
184         return super(mail_group, self).write(cr, uid, ids, vals, context=context)
185
186     def action_group_join(self, cr, uid, ids, context=None):
187         return self.message_subscribe(cr, uid, ids, context=context)
188
189     def action_group_leave(self, cr, uid, ids, context=None):
190         return self.message_unsubscribe(cr, uid, ids, context=context)