[MERGE] base: raise an exception if the format of the bank account is wrong
[odoo/odoo.git] / openerp / addons / base / res / res_users.py
index 31f6c71..5e1ea88 100644 (file)
@@ -3,7 +3,7 @@
 #
 #    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
@@ -26,6 +26,7 @@ import logging
 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
@@ -185,10 +186,10 @@ class res_users(osv.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)
@@ -206,11 +207,6 @@ class res_users(osv.osv):
         ('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
@@ -238,9 +234,9 @@ class res_users(osv.osv):
         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
@@ -248,13 +244,14 @@ class res_users(osv.osv):
         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):
@@ -265,7 +262,7 @@ class res_users(osv.osv):
         """
         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']
@@ -279,11 +276,11 @@ class res_users(osv.osv):
                     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)
@@ -305,7 +302,7 @@ class res_users(osv.osv):
             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:
@@ -328,10 +325,10 @@ class res_users(osv.osv):
                        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_'):
@@ -349,9 +346,60 @@ class res_users(osv.osv):
 
     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
@@ -370,8 +418,8 @@ class res_users(osv.osv):
             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")
@@ -379,54 +427,8 @@ class res_users(osv.osv):
                     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
@@ -435,32 +437,14 @@ class res_users(osv.osv):
             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
@@ -554,7 +538,7 @@ class groups_implied(osv.osv):
             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
 
@@ -583,8 +567,6 @@ class groups_implied(osv.osv):
                 super(groups_implied, self).write(cr, uid, gids, vals, context)
         return res
 
-groups_implied()
-
 class users_implied(osv.osv):
     _inherit = 'res.users'
 
@@ -608,10 +590,6 @@ class users_implied(osv.osv):
                 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:
@@ -705,7 +683,7 @@ class groups_view(osv.osv):
 
     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
@@ -754,8 +732,6 @@ class groups_view(osv.osv):
             res.append((False, 'boolean', others))
         return res
 
-groups_view()
-
 class users_view(osv.osv):
     _inherit = 'res.users'
 
@@ -847,6 +823,4 @@ class users_view(osv.osv):
                     }
         return res
 
-users_view()
-
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: