1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2011 Tiny SPRL (<http://tiny.be>).
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 ##############################################################################
22 from osv import osv, fields
25 class portal(osv.osv):
27 _description = 'Portal'
29 'name': fields.char(string='Name', size=64, required=True),
30 'menu_id': fields.many2one('ir.actions.actions', required="True",
32 help="The customized menu of the portal's users"),
33 'user_ids': fields.one2many('res.users', 'portal_id',
35 help='Gives the set of users associated to this portal'),
36 'group_ids': fields.many2many('res.groups', 'res_portals_groups_rel', 'pid', 'gid',
38 help='Users of this portal automatically belong to those groups'),
41 ('unique_name', 'UNIQUE(name)', 'Portals must have different names.')
44 def copy(self, cr, uid, id, defaults, context=None):
45 """ override copy() to not copy the portal users """
46 # find an unused name of the form "old_name [N]" for some random N
47 old_name = self.browse(cr, uid, id, context).name
48 new_name = copy_random(old_name)
49 while self.search(cr, uid, [('name', '=', new_name)], limit=1, context=context):
50 new_name = copy_random(old_name)
52 defaults['name'] = new_name
53 defaults['user_ids'] = []
54 return super(portal, self).copy(cr, uid, id, defaults, context)
56 def create(self, cr, uid, values, context=None):
57 """ extend create() to assign the portal menu and groups to users """
58 # as 'user_ids' is a many2one relation, values['user_ids'] must be a
59 # list of tuples of the form (0, 0, {values})
60 for op, _, user_values in values['user_ids']:
62 user_values['menu_id'] = values['menu_id']
63 user_values['groups_id'] = values['group_ids']
65 return super(portal, self).create(cr, uid, values, context)
67 def write(self, cr, uid, ids, values, context=None):
68 """ extend write() to reflect menu and groups changes on users """
70 # analyse groups changes, and determine how to change users
72 for change in values.get('group_ids', []):
73 if change[0] in [0, 5, 6]: # change creates or sets groups,
74 groups_diff = None # must compute per-portal diff
76 if change[0] in [3, 4]: # change add or remove group,
77 groups_diff.append(change) # add or remove group on users
79 if groups_diff is None:
80 return self._write_compute_diff(cr, uid, ids, values, context)
82 return self._write_diff(cr, uid, ids, values, groups_diff, context)
84 def _write_diff(self, cr, uid, ids, values, groups_diff, context=None):
85 """ perform write() and apply groups_diff on users """
86 # first apply portal changes
87 super(portal, self).write(cr, uid, ids, values, context)
89 # then apply menu and group changes on their users
91 if 'menu_id' in values:
92 user_values['menu_id'] = values['menu_id']
94 user_values['groups_id'] = groups_diff
98 for p in self.browse(cr, uid, ids, context):
99 user_ids += get_browse_ids(p.user_ids)
100 self.pool.get('res.users').write(cr, uid, user_ids, user_values, context)
104 def _write_compute_diff(self, cr, uid, ids, values, context=None):
105 """ perform write(), then compute and apply groups_diff on each portal """
106 # read group_ids before write() to compute groups_diff
108 for p in self.browse(cr, uid, ids, context):
109 old_group_ids[p.id] = get_browse_ids(p.group_ids)
111 # apply portal changes
112 super(portal, self).write(cr, uid, ids, values, context)
114 # the changes to apply on users
116 if 'menu_id' in values:
117 user_values['menu_id'] = values['menu_id']
119 # compute groups_diff on each portal, and apply them on users
120 for p in self.browse(cr, uid, ids, context):
121 old_groups = set(old_group_ids[p.id])
122 new_groups = set(get_browse_ids(p.group_ids))
123 # groups_diff: [(3, UNLINKED_ID), ..., (4, LINKED_ID), ...]
124 user_values['groups_id'] = \
125 [(3, g) for g in (old_groups - new_groups)] + \
126 [(4, g) for g in (new_groups - old_groups)]
127 user_ids = get_browse_ids(p.user_ids)
128 self.pool.get('res.users').write(cr, uid, user_ids, user_values, context)
134 class users(osv.osv):
136 _inherit = 'res.users'
138 'portal_id': fields.many2one('res.portal', string='Portal',
139 help='If given, the portal defines customized menu and access rules'),
145 def get_browse_id(obj):
146 """ return the id of a browse() object, or None """
147 return (obj and obj.id or None)
149 def get_browse_ids(objs):
150 """ return the ids of a list of browse() objects """
151 return map(get_browse_id, objs)
153 def copy_random(name):
154 """ return "name [N]" for some random integer N """
155 return "%s [%s]" % (name, random.choice(xrange(1000000)))