import itertools
import logging
from functools import partial
+from itertools import repeat
from lxml import etree
from lxml.builder import E
'login_date': fields.date('Latest connection', select=1),
'partner_id': fields.many2one('res.partner', required=True,
string='Related Partner', ondelete='restrict',
- help='Partner-related data of the user'),
+ help='Partner-related data of the user', auto_join=True),
'login': fields.char('Login', size=64, required=True,
help="Used to log into the system"),
'password': fields.char('Password', size=64, invisible=True, copy=False,
'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'),
}
+ # overridden inherited fields to bypass access rights, in case you have
+ # access to the user but not its corresponding partner
+ name = openerp.fields.Char(related='partner_id.name')
+ email = openerp.fields.Char(related='partner_id.email')
+
def on_change_login(self, cr, uid, ids, login, context=None):
if login and tools.single_email_re.match(login):
return {'value': {'email': login}}
# Naming conventions for reified groups fields:
# - boolean field 'in_group_ID' is True iff
# ID is in 'groups_id'
-# - boolean field 'in_groups_ID1_..._IDk' is True iff
-# any of ID1, ..., IDk is in 'groups_id'
# - selection field 'sel_groups_ID1_..._IDk' is ID iff
# ID is in 'groups_id' and ID is maximal in the set {ID1, ..., IDk}
#----------------------------------------------------------
-def name_boolean_group(id): return 'in_group_' + str(id)
-def name_boolean_groups(ids): return 'in_groups_' + '_'.join(map(str, ids))
-def name_selection_groups(ids): return 'sel_groups_' + '_'.join(map(str, ids))
+def name_boolean_group(id):
+ return 'in_group_' + str(id)
+
+def name_selection_groups(ids):
+ return 'sel_groups_' + '_'.join(map(str, ids))
+
+def is_boolean_group(name):
+ return name.startswith('in_group_')
+
+def is_selection_groups(name):
+ return name.startswith('sel_groups_')
-def is_boolean_group(name): return name.startswith('in_group_')
-def is_boolean_groups(name): return name.startswith('in_groups_')
-def is_selection_groups(name): return name.startswith('sel_groups_')
def is_reified_group(name):
- return is_boolean_group(name) or is_boolean_groups(name) or is_selection_groups(name)
+ return is_boolean_group(name) or is_selection_groups(name)
+
+def get_boolean_group(name):
+ return int(name[9:])
-def get_boolean_group(name): return int(name[9:])
-def get_boolean_groups(name): return map(int, name[10:].split('_'))
-def get_selection_groups(name): return map(int, name[11:].split('_'))
+def get_selection_groups(name):
+ return map(int, name[11:].split('_'))
def partition(f, xs):
"return a pair equivalent to (filter(f, xs), filter(lambda x: not f(x), xs))"
_inherit = 'res.users'
def create(self, cr, uid, values, context=None):
- self._set_reified_groups(values)
+ values = self._remove_reified_groups(values)
return super(users_view, self).create(cr, uid, values, context)
def write(self, cr, uid, ids, values, context=None):
- self._set_reified_groups(values)
+ values = self._remove_reified_groups(values)
return super(users_view, self).write(cr, uid, ids, values, context)
- def _set_reified_groups(self, values):
- """ reflect reified group fields in values['groups_id'] """
- if 'groups_id' in values:
- # groups are already given, ignore group fields
- for f in filter(is_reified_group, values.iterkeys()):
- del values[f]
- return
+ def _remove_reified_groups(self, values):
+ """ return `values` without reified group fields """
+ add, rem = [], []
+ values1 = {}
+
+ for key, val in values.iteritems():
+ if is_boolean_group(key):
+ (add if val else rem).append(get_boolean_group(key))
+ elif is_selection_groups(key):
+ rem += get_selection_groups(key)
+ if val:
+ add.append(val)
+ else:
+ values1[key] = val
- add, remove = [], []
- for f in values.keys():
- if is_boolean_group(f):
- target = add if values.pop(f) else remove
- target.append(get_boolean_group(f))
- elif is_boolean_groups(f):
- if not values.pop(f):
- remove.extend(get_boolean_groups(f))
- elif is_selection_groups(f):
- remove.extend(get_selection_groups(f))
- selected = values.pop(f)
- if selected:
- add.append(selected)
- # update values *only* if groups are being modified, otherwise
- # we introduce spurious changes that might break the super.write() call.
- if add or remove:
- # remove groups in 'remove' and add groups in 'add'
- values['groups_id'] = [(3, id) for id in remove] + [(4, id) for id in add]
+ if 'groups_id' not in values and (add or rem):
+ # remove group ids in `rem` and add group ids in `add`
+ values1['groups_id'] = zip(repeat(3), rem) + zip(repeat(4), add)
+
+ return values1
def default_get(self, cr, uid, fields, context=None):
group_fields, fields = partition(is_reified_group, fields)
fields1 = (fields + ['groups_id']) if group_fields else fields
values = super(users_view, self).default_get(cr, uid, fields1, context)
- self._get_reified_groups(group_fields, values)
+ self._add_reified_groups(group_fields, values)
# add "default_groups_ref" inside the context to set default value for group_id with xml values
if 'groups_id' in fields and isinstance(context.get("default_groups_ref"), list):
return values
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
- fields_get = fields if fields is not None else self.fields_get(cr, uid, context=context).keys()
- group_fields, _ = partition(is_reified_group, fields_get)
+ # determine whether reified groups fields are required, and which ones
+ fields1 = fields or self.fields_get(cr, uid, context=context).keys()
+ group_fields, other_fields = partition(is_reified_group, fields1)
+
+ # read regular fields (other_fields); add 'groups_id' if necessary
+ drop_groups_id = False
+ if group_fields and fields:
+ if 'groups_id' not in other_fields:
+ other_fields.append('groups_id')
+ drop_groups_id = True
+ else:
+ other_fields = fields
- inject_groups_id = group_fields and fields and 'groups_id' not in fields
- if inject_groups_id:
- fields.append('groups_id')
- res = super(users_view, self).read(cr, uid, ids, fields, context=context, load=load)
+ res = super(users_view, self).read(cr, uid, ids, other_fields, context=context, load=load)
- if res and group_fields:
+ # post-process result to add reified group fields
+ if group_fields:
for values in (res if isinstance(res, list) else [res]):
- self._get_reified_groups(group_fields, values)
- if inject_groups_id:
+ self._add_reified_groups(group_fields, values)
+ if drop_groups_id:
values.pop('groups_id', None)
return res
- def _get_reified_groups(self, fields, values):
- """ compute the given reified group fields from values['groups_id'] """
+ def _add_reified_groups(self, fields, values):
+ """ add the given reified group fields into `values` """
gids = set(parse_m2m(values.get('groups_id') or []))
for f in fields:
if is_boolean_group(f):
values[f] = get_boolean_group(f) in gids
- elif is_boolean_groups(f):
- values[f] = not gids.isdisjoint(get_boolean_groups(f))
elif is_selection_groups(f):
selected = [gid for gid in get_selection_groups(f) if gid in gids]
values[f] = selected and selected[-1] or False
'user_ids': fields.one2many('change.password.user', 'wizard_id', string='Users'),
}
- def default_get(self, cr, uid, fields, context=None):
- if context == None:
+ def _default_user_ids(self, cr, uid, context=None):
+ if context is None:
context = {}
- user_ids = context.get('active_ids', [])
- wiz_id = context.get('active_id', None)
- res = []
- users = self.pool.get('res.users').browse(cr, uid, user_ids, context=context)
- for user in users:
- res.append((0, 0, {
- 'wizard_id': wiz_id,
- 'user_id': user.id,
- 'user_login': user.login,
- }))
- return {'user_ids': res}
-
- def change_password_button(self, cr, uid, id, context=None):
- wizard = self.browse(cr, uid, id, context=context)[0]
+ user_model = self.pool['res.users']
+ user_ids = context.get('active_model') == 'res.users' and context.get('active_ids') or []
+ return [
+ (0, 0, {'user_id': user.id, 'user_login': user.login})
+ for user in user_model.browse(cr, uid, user_ids, context=context)
+ ]
+
+ _defaults = {
+ 'user_ids': _default_user_ids,
+ }
+
+ def change_password_button(self, cr, uid, ids, context=None):
+ wizard = self.browse(cr, uid, ids, context=context)[0]
need_reload = any(uid == user.user_id.id for user in wizard.user_ids)
- line_ids = [user.id for user in wizard.user_ids]
+ line_ids = [user.id for user in wizard.user_ids]
self.pool.get('change.password.user').change_password_button(cr, uid, line_ids, context=context)
- # don't keep temporary password copies in the database longer than necessary
- self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context)
if need_reload:
return {
}
def change_password_button(self, cr, uid, ids, context=None):
- for user in self.browse(cr, uid, ids, context=context):
- self.pool.get('res.users').write(cr, uid, user.user_id.id, {'password': user.new_passwd})
+ for line in self.browse(cr, uid, ids, context=context):
+ line.user_id.write({'password': line.new_passwd})
+ # don't keep temporary passwords in the database longer than necessary
+ self.write(cr, uid, ids, {'new_passwd': False}, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: