#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
+# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
from lxml import etree
from lxml.builder import E
import netsvc
+from openerp import SUPERUSER_ID
import openerp
import openerp.exceptions
from osv import fields,osv
if 'password' in o and ( 'id' not in o or o['id'] != uid ):
o['password'] = '********'
return o
- result = super(users, self).read(cr, uid, ids, fields, context, load)
+ result = super(res_users, self).read(cr, uid, ids, fields, context, load)
canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False)
if not canwrite:
- if isinstance(ids, (int, float)):
+ if isinstance(ids, (int, long)):
result = override_password(result)
else:
result = map(override_password, result)
('login_key', 'UNIQUE (login)', 'You can not have two users with the same login !')
]
- def _get_default_image(self, cr, uid, is_company, context=None):
- """ Override of res.partner: multicolor avatars ! """
- image_path = openerp.modules.get_module_resource('base', 'static/src/img', 'avatar%d.png' % random.randint(0, 6))
- return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
-
def _get_company(self,cr, uid, context=None, uid2=False):
if not uid2:
uid2 = uid
dataobj = self.pool.get('ir.model.data')
result = []
try:
- dummy,group_id = dataobj.get_object_reference(cr, 1, 'base', 'group_user')
+ dummy,group_id = dataobj.get_object_reference(cr, SUPERUSER_ID, 'base', 'group_user')
result.append(group_id)
- dummy,group_id = dataobj.get_object_reference(cr, 1, 'base', 'group_partner_manager')
+ dummy,group_id = dataobj.get_object_reference(cr, SUPERUSER_ID, 'base', 'group_partner_manager')
result.append(group_id)
except ValueError:
# If these groups does not exists anymore
return result
_defaults = {
- 'password' : '',
- 'active' : True,
+ 'password': '',
+ 'active': True,
'customer': False,
'menu_id': _get_menu,
'company_id': _get_company,
'company_ids': _get_companies,
'groups_id': _get_group,
+ 'image': lambda self, cr, uid, ctx={}: self.pool.get('res.partner')._get_default_image(cr, uid, False, ctx, colorize=True),
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
if not view_id and view_type == 'form':
return self.pool.get('res.partner').fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
- return super(users, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
+ return super(res_users, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
# User can write to a few of her own fields (but not her groups for example)
SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small']
break
else:
if 'company_id' in values:
- if not (values['company_id'] in self.read(cr, 1, uid, ['company_ids'], context=context)['company_ids']):
+ if not (values['company_id'] in self.read(cr, SUPERUSER_ID, uid, ['company_ids'], context=context)['company_ids']):
del values['company_id']
uid = 1 # safe fields only, so we write as super-user to bypass access rights
- res = super(users, self).write(cr, uid, ids, values, context=context)
+ res = super(res_users, self).write(cr, uid, ids, values, context=context)
# clear caches linked to the users
self.pool.get('ir.model.access').call_cache_clearing_methods(cr)
for id in ids:
if id in self._uid_cache[db]:
del self._uid_cache[db][id]
- return super(users, self).unlink(cr, uid, ids, context=context)
+ return super(res_users, self).unlink(cr, uid, ids, context=context)
def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
if not args:
name=(copy_pattern % user2copy['name']),
)
copydef.update(default)
- return super(users, self).copy(cr, uid, id, copydef, context)
+ return super(res_users, self).copy(cr, uid, id, copydef, context)
def context_get(self, cr, uid, context=None):
- user = self.browse(cr, uid, uid, context)
+ user = self.browse(cr, SUPERUSER_ID, uid, context)
result = {}
for k in self._all_columns.keys():
if k.startswith('context_'):
def action_get(self, cr, uid, context=None):
dataobj = self.pool.get('ir.model.data')
- data_id = dataobj._get_id(cr, 1, 'base', 'action_res_users_my')
+ data_id = dataobj._get_id(cr, SUPERUSER_ID, 'base', 'action_res_users_my')
return dataobj.browse(cr, uid, data_id, context=context).res_id
+ def check_super(self, passwd):
+ if passwd == tools.config['admin_passwd']:
+ return True
+ else:
+ raise openerp.exceptions.AccessDenied()
+
+ def check_credentials(self, cr, uid, password):
+ """ Override this method to plug additional authentication methods"""
+ res = self.search(cr, SUPERUSER_ID, [('id','=',uid),('password','=',password)])
+ if not res:
+ raise openerp.exceptions.AccessDenied()
+
+ def login(self, db, login, password):
+ if not password:
+ return False
+ user_id = False
+ cr = pooler.get_db(db).cursor()
+ try:
+ # autocommit: our single update request will be performed atomically.
+ # (In this way, there is no opportunity to have two transactions
+ # interleaving their cr.execute()..cr.commit() calls and have one
+ # of them rolled back due to a concurrent access.)
+ cr.autocommit(True)
+ # check if user exists
+ res = self.search(cr, SUPERUSER_ID, [('login','=',login)])
+ if res:
+ user_id = res[0]
+ # check credentials
+ self.check_credentials(cr, user_id, password)
+ # We effectively unconditionally write the res_users line.
+ # Even w/ autocommit there's a chance the user row will be locked,
+ # in which case we can't delay the login just for the purpose of
+ # update the last login date - hence we use FOR UPDATE NOWAIT to
+ # try to get the lock - fail-fast
+ # Failing to acquire the lock on the res_users row probably means
+ # another request is holding it. No big deal, we don't want to
+ # prevent/delay login in that case. It will also have been logged
+ # as a SQL error, if anyone cares.
+ try:
+ cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", str(user_id))
+ cr.execute("UPDATE res_users SET login_date = now() AT TIME ZONE 'UTC' WHERE id=%s", str(user_id))
+ except Exception, e:
+ _logger.exception("Failed to update last_login for db:%s login:%s", db, login)
+ except openerp.exceptions.AccessDenied:
+ _logger.info("Login failed for db:%s login:%s", db, login)
+ user_id = False
+ finally:
+ cr.close()
+
+ return user_id
+
def authenticate(self, db, login, password, user_agent_env):
"""Verifies and returns the user ID corresponding to the given
``login`` and ``password`` combination, or False if there was
if user_agent_env and user_agent_env.get('base_location'):
cr = pooler.get_db(db).cursor()
try:
- self.pool.get('ir.config_parameter').set_param(cr, uid, 'web.base.url',
- user_agent_env['base_location'])
+ base = user_agent_env['base_location']
+ self.pool.get('ir.config_parameter').set_param(cr, uid, 'web.base.url', base)
cr.commit()
except Exception:
_logger.exception("Failed to update web.base.url configuration parameter")
cr.close()
return uid
- def login(self, db, login, password):
- if not password:
- return False
- cr = pooler.get_db(db).cursor()
- try:
- # autocommit: our single request will be performed atomically.
- # (In this way, there is no opportunity to have two transactions
- # interleaving their cr.execute()..cr.commit() calls and have one
- # of them rolled back due to a concurrent access.)
- # We effectively unconditionally write the res_users line.
- cr.autocommit(True)
- # Even w/ autocommit there's a chance the user row will be locked,
- # in which case we can't delay the login just for the purpose of
- # update the last login date - hence we use FOR UPDATE NOWAIT to
- # try to get the lock - fail-fast
- cr.execute("""SELECT id from res_users
- WHERE login=%s AND password=%s
- AND active FOR UPDATE NOWAIT""",
- (tools.ustr(login), tools.ustr(password)))
- cr.execute("""UPDATE res_users
- SET login_date = now() AT TIME ZONE 'UTC'
- WHERE login=%s AND password=%s AND active
- RETURNING id""",
- (tools.ustr(login), tools.ustr(password)))
- except Exception:
- # Failing to acquire the lock on the res_users row probably means
- # another request is holding it. No big deal, we don't want to
- # prevent/delay login in that case. It will also have been logged
- # as a SQL error, if anyone cares.
- cr.execute("""SELECT id from res_users
- WHERE login=%s AND password=%s
- AND active""",
- (tools.ustr(login), tools.ustr(password)))
- finally:
- res = cr.fetchone()
- cr.close()
- if res:
- return res[0]
- return False
-
- def check_super(self, passwd):
- if passwd == tools.config['admin_passwd']:
- return True
- else:
- raise openerp.exceptions.AccessDenied()
-
def check(self, db, uid, passwd):
- """Verifies that the given (uid, password) pair is authorized for the database ``db`` and
+ """Verifies that the given (uid, password) is authorized for the database ``db`` and
raise an exception if it is not."""
if not passwd:
# empty passwords disallowed for obvious security reasons
return
cr = pooler.get_db(db).cursor()
try:
- cr.execute('SELECT COUNT(1) FROM res_users WHERE id=%s AND password=%s AND active=%s',
- (int(uid), passwd, True))
- res = cr.fetchone()[0]
- if not res:
- raise openerp.exceptions.AccessDenied()
+ self.check_credentials(cr, uid, passwd)
if self._uid_cache.has_key(db):
- ulist = self._uid_cache[db]
- ulist[uid] = passwd
+ self._uid_cache[db][uid] = passwd
else:
self._uid_cache[db] = {uid:passwd}
finally:
cr.close()
- def access(self, db, uid, passwd, sec_level, ids):
- if not passwd:
- return False
- cr = pooler.get_db(db).cursor()
- try:
- cr.execute('SELECT id FROM res_users WHERE id=%s AND password=%s', (uid, passwd))
- res = cr.fetchone()
- if not res:
- raise openerp.exceptions.AccessDenied()
- return res[0]
- finally:
- cr.close()
-
def change_password(self, cr, uid, old_passwd, new_passwd, context=None):
"""Change current user password. Old password must be provided explicitly
to prevent hijacking an existing user session, or for cases where the cleartext
return memo[g]
res = {}
- for g in self.browse(cr, 1, ids, context):
+ for g in self.browse(cr, SUPERUSER_ID, ids, context):
res[g.id] = map(int, computed_set(g))
return res
super(groups_implied, self).write(cr, uid, gids, vals, context)
return res
-groups_implied()
-
class users_implied(osv.osv):
_inherit = 'res.users'
super(users_implied, self).write(cr, uid, [user.id], vals, context)
return res
-users_implied()
-
-
-
#
# Extension of res.groups and res.users for the special groups view in the users
# form. This extension presents groups with selection and boolean widgets:
def get_user_groups_view(self, cr, uid, context=None):
try:
- view = self.pool.get('ir.model.data').get_object(cr, 1, 'base', 'user_groups_view', context)
+ view = self.pool.get('ir.model.data').get_object(cr, SUPERUSER_ID, 'base', 'user_groups_view', context)
assert view and view._table_name == 'ir.ui.view'
except Exception:
view = False
res.append((False, 'boolean', others))
return res
-groups_view()
-
class users_view(osv.osv):
_inherit = 'res.users'
}
return res
-users_view()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: