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