[MERGE] mail/chatter complete review/refactoring
[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.Model):
31     """ A mail_group is a collection of users sharing messages in a discussion
32         group. The group mechanics are based on the followers. """
33     _description = 'Discussion group'
34     _name = 'mail.group'
35     _inherit = ['mail.thread']
36     _inherits = {'mail.alias': 'alias_id', 'ir.ui.menu': 'menu_id'}
37
38     def _get_image(self, cr, uid, ids, name, args, context=None):
39         result = dict.fromkeys(ids, False)
40         for obj in self.browse(cr, uid, ids, context=context):
41             result[obj.id] = tools.image_get_resized_images(obj.image)
42         return result
43
44     def _set_image(self, cr, uid, id, name, value, args, context=None):
45         return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
46
47     _columns = {
48         'description': fields.text('Description'),
49         'menu_id': fields.many2one('ir.ui.menu', string='Related Menu', required=True, ondelete="cascade"),
50         'public': fields.selection([('public','Public'),('private','Private'),('groups','Selected Group Only')], 'Privacy', required=True,
51             help='This group is visible by non members. \
52             Invisible groups can add members through the invite button.'),
53         'group_public_id': fields.many2one('res.groups', string='Authorized Group'),
54         'group_ids': fields.many2many('res.groups', rel='mail_group_res_group_rel',
55             id1='mail_group_id', id2='groups_id', string='Auto Subscription',
56             help="Members of those groups will automatically added as followers. "\
57                  "Note that they will be able to manage their subscription manually "\
58                  "if necessary."),
59         'image': fields.binary("Photo",
60             help="This field holds the image used as photo for the "\
61                  "user. The image is base64 encoded, and PIL-supported. "\
62                  "It is limited to a 1024x1024 px image."),
63         'image_medium': fields.function(_get_image, fnct_inv=_set_image,
64             string="Medium-sized photo", type="binary", multi="_get_image",
65             store = {
66                 'mail.group': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
67             },
68             help="Medium-sized photo of the group. It is automatically "\
69                  "resized as a 180x180px image, with aspect ratio preserved. "\
70                  "Use this field in form views or some kanban views."),
71         'image_small': fields.function(_get_image, fnct_inv=_set_image,
72             string="Small-sized photo", type="binary", multi="_get_image",
73             store = {
74                 'mail.group': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
75             },
76             help="Small-sized photo of the group. It is automatically "\
77                  "resized as a 50x50px image, with aspect ratio preserved. "\
78                  "Use this field anywhere a small image is required."),
79         'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True,
80             help="The email address associated with this group. New emails received will automatically "
81                  "create new topics."),
82     }
83
84     def _get_default_employee_group(self, cr, uid, context=None):
85         ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
86         return ref and ref[1] or False
87
88     def _get_default_image(self, cr, uid, context=None):
89         image_path = openerp.modules.get_module_resource('mail', 'static/src/img', 'groupdefault.png')
90         return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
91
92     def _get_menu_parent(self, cr, uid, context=None):
93         ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'mail_group_root')
94         return ref and ref[1] or False
95
96     _defaults = {
97         'public': 'groups',
98         'group_public_id': _get_default_employee_group,
99         'image': _get_default_image,
100         'parent_id': _get_menu_parent,
101         'alias_domain': False, # always hide alias during creation
102     }
103
104     def _subscribe_users(self, cr, uid, ids, context=None):
105         for mail_group in self.browse(cr, uid, ids, context=context):
106             partner_ids = []
107             for group in mail_group.group_ids:
108                 partner_ids += [user.partner_id.id for user in group.users]
109             self.message_subscribe(cr, uid, ids, partner_ids, context=context)
110
111     def create(self, cr, uid, vals, context=None):
112         mail_alias = self.pool.get('mail.alias')
113         if not vals.get('alias_id'):
114             vals.pop('alias_name', None) # prevent errors during copy()
115             alias_id = mail_alias.create_unique_alias(cr, uid,
116                           # Using '+' allows using subaddressing for those who don't
117                           # have a catchall domain setup.
118                           {'alias_name': "group+"+vals['name']},
119                           model_name=self._name, context=context)
120             vals['alias_id'] = alias_id
121
122         mail_group_id = super(mail_group, self).create(cr, uid, vals, context)
123
124         # Create client action for this group and link the menu to it
125         ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'action_mail_group_feeds')
126         if ref:
127             search_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'view_message_search')
128             params = {
129                 'search_view_id': search_ref and search_ref[1] or False,
130                 'domain': [('model','=','mail.group'), ('res_id','=',mail_group_id)],
131                 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id},
132                 'res_model': 'mail.message',
133                 'thread_level': 1,
134             }
135             cobj = self.pool.get('ir.actions.client')
136             newref = cobj.copy(cr, uid, ref[1], default={'params': str(params), 'name': vals['name']}, context=context)
137             self.write(cr, uid, [mail_group_id], {'action': 'ir.actions.client,'+str(newref), 'mail_group_id': mail_group_id}, context=context)
138
139         mail_alias.write(cr, uid, [vals['alias_id']], {"alias_force_thread_id": mail_group_id}, context)
140
141         if vals.get('group_ids'):
142             self._subscribe_users(cr, uid, [mail_group_id], context=context)
143         return mail_group_id
144
145     def unlink(self, cr, uid, ids, context=None):
146         # Cascade-delete mail aliases as well, as they should not exist without the mail group.
147         mail_alias = self.pool.get('mail.alias')
148         alias_ids = [group.alias_id.id for group in self.browse(cr, uid, ids, context=context) if group.alias_id]
149         res = super(mail_group, self).unlink(cr, uid, ids, context=context)
150         mail_alias.unlink(cr, uid, alias_ids, context=context)
151         return res
152
153     def write(self, cr, uid, ids, vals, context=None):
154         result = super(mail_group, self).write(cr, uid, ids, vals, context=context)
155         if vals.get('group_ids'):
156             self._subscribe_users(cr, uid, ids, vals.get('group_ids'), context=context)
157         return result
158
159     def action_follow(self, cr, uid, ids, context=None):
160         """ Wrapper because message_subscribe_users take a user_ids=None
161             that receive the context without the wrapper. """
162         return self.message_subscribe_users(cr, uid, ids, context=context)
163
164     def action_unfollow(self, cr, uid, ids, context=None):
165         """ Wrapper because message_unsubscribe_users take a user_ids=None
166             that receive the context without the wrapper. """
167         return self.message_unsubscribe_users(cr, uid, ids, context=context)