1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2010-today OpenERP SA (<http://www.openerp.com>)
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
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
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/>
20 ##############################################################################
25 import openerp.tools as tools
26 from operator import itemgetter
28 from osv import fields
32 from tools.translate import _
33 from lxml import etree
35 class mail_group(osv.osv):
37 A mail_group is a collection of users sharing messages in a discussion
38 group. Group users are users that follow the mail group, using the
39 subscription/follow mechanism of OpenSocial. A mail group has nothing
40 in common wih res.users.group.
41 Additional information on fields:
42 - ``member_ids``: user member of the groups are calculated with
43 ``message_get_subscribers`` method from mail.thread
44 - ``member_count``: calculated with member_ids
45 - ``is_subscriber``: calculated with member_ids
49 _description = 'Discussion group'
51 _inherit = ['mail.thread']
52 _inherits = {'mail.alias': 'alias_id'}
53 def action_group_join(self, cr, uid, ids, context={}):
54 return self.message_subscribe(cr, uid, ids, context=context);
56 def action_group_leave(self, cr, uid, ids, context={}):
57 return self.message_unsubscribe(cr, uid, ids, context=context);
59 def onchange_photo(self, cr, uid, ids, value, context=None):
61 return {'value': {'avatar_big': value, 'avatar': value} }
62 return {'value': {'photo_big': value, 'photo': self._photo_resize(cr, uid, value) } }
64 def _set_photo(self, cr, uid, id, name, value, args, context=None):
66 return self.write(cr, uid, [id], {'photo_big': value}, context=context)
68 return self.write(cr, uid, [id], {'photo_big': value}, context=context)
70 def _photo_resize(self, cr, uid, photo, width=128, height=128, context=None):
71 image_stream = io.BytesIO(photo.decode('base64'))
72 img = Image.open(image_stream)
73 img.thumbnail((width, height), Image.ANTIALIAS)
74 img_stream = StringIO.StringIO()
75 img.save(img_stream, "JPEG")
76 return img_stream.getvalue().encode('base64')
78 def _get_photo(self, cr, uid, ids, name, args, context=None):
79 result = dict.fromkeys(ids, False)
80 for group in self.browse(cr, uid, ids, context=context):
82 result[group.id] = self._photo_resize(cr, uid, group.photo_big, context=context)
85 def get_member_ids(self, cr, uid, ids, field_names, args, context=None):
88 result = dict.fromkeys(ids)
91 result[id]['member_ids'] = self.message_get_subscribers_ids(cr, uid, [id], context=context)
92 result[id]['member_count'] = len(result[id]['member_ids'])
93 result[id]['is_subscriber'] = uid in result[id]['member_ids']
96 def search_member_ids(self, cr, uid, obj, name, args, context=None):
99 sub_obj = self.pool.get('mail.subscription')
100 sub_ids = sub_obj.search(cr, uid, ['&', ('res_model', '=', obj._name), ('user_id', '=', args[0][2])], context=context)
101 subs = sub_obj.read(cr, uid, sub_ids, context=context)
102 return [('id', 'in', map(itemgetter('res_id'), subs))]
104 def get_last_month_msg_nbr(self, cr, uid, ids, name, args, context=None):
106 message_obj = self.pool.get('mail.message')
108 lower_date = (DT.datetime.now() - DT.timedelta(days=30)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
109 result[id] = message_obj.search(cr, uid, ['&', '&', ('model', '=', self._name), ('res_id', 'in', ids), ('date', '>=', lower_date)], count=True, context=context)
112 def _get_default_photo(self, cr, uid, context=None):
113 avatar_path = openerp.modules.get_module_resource('mail', 'static/src/img', 'groupdefault.png')
114 return self._photo_resize(cr, uid, open(avatar_path, 'rb').read().encode('base64'), context=context)
117 'name': fields.char('Name', size=64, required=True),
118 'description': fields.text('Description'),
119 'responsible_id': fields.many2one('res.users', string='Responsible',
120 ondelete='set null', required=True, select=1,
121 help="Responsible of the group that has all rights on the record."),
122 'public': fields.boolean('Public', help='This group is visible by non members. Invisible groups can add members through the invite button.'),
123 'photo_big': fields.binary('Full-size photo', help='Field holding the full-sized PIL-supported and base64 encoded version of the group image. The photo field is used as an interface for this field.'),
124 'photo': fields.function(_get_photo, fnct_inv=_set_photo, string='Photo', type="binary",
126 'mail.group': (lambda self, cr, uid, ids, c={}: ids, ['photo_big'], 10),
127 }, help='Field holding the automatically resized (128x128) PIL-supported and base64 encoded version of the group image.'),
128 'member_ids': fields.function(get_member_ids, fnct_search=search_member_ids, type='many2many',
129 relation='res.users', string='Group members', multi='get_member_ids'),
130 'member_count': fields.function(get_member_ids, type='integer', string='Member count', multi='get_member_ids'),
131 'is_subscriber': fields.function(get_member_ids, type='boolean', string='Joined', multi='get_member_ids'),
132 'last_month_msg_nbr': fields.function(get_last_month_msg_nbr, type='integer', string='Messages count for last month'),
133 'alias_id': fields.many2one('mail.alias', 'Mail Alias', ondelete="cascade", required=True,
134 help="This Unique Mail Box Alias of the Group allows to manage the Seamless email communication between Mail Box and OpenERP,"
135 "This Alias MailBox manage the Group email communication.")
140 'responsible_id': (lambda s, cr, uid, ctx: uid),
141 'photo': _get_default_photo,
144 def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
145 res = super(mail_group,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
146 if view_type == 'form':
147 domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "mail.catchall.domain", context=context)
149 doc = etree.XML(res['arch'])
150 alias_node = doc.xpath("//field[@name='alias_id']")[0]
151 parent = alias_node.getparent()
152 parent.remove(alias_node)
153 res['arch'] = etree.tostring(doc)
156 def create(self, cr, uid, vals, context=None):
157 alias_pool = self.pool.get('mail.alias')
158 if not vals.get('alias_id'):
159 alias_id = alias_pool.create_unique_alias(cr, uid, {'alias_name': "mail_group."+vals['name'], 'alias_model_id': self._name}, context=context)
160 vals.update({'alias_id': alias_id})
161 res = super(mail_group, self).create(cr, uid, vals, context)
162 alias_pool.write(cr, uid, [vals['alias_id']], {"alias_force_thread_id": res}, context)