From fa9a3e66306dc8d7f68f943f1aa5d3b1e5e0136e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 18:02:41 +0200 Subject: [PATCH 1/9] [IMP] res_users: added readable files, to allow people like portal users to see their name and basic data when logging... bzr revid: tde@openerp.com-20120917160241-k96a24nf60jgr0h8 --- openerp/addons/base/res/res_users.py | 45 +++++++++++++++++----------- openerp/osv/osv.py | 1 + 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 1f0d612468f..1b167ff5077 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -193,21 +193,6 @@ class res_users(osv.osv): partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)] return self.pool.get('res.partner').onchange_address(cr, uid, partner_ids, use_parent_address, parent_id, context=context) - def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'): - def override_password(o): - if 'password' in o and ( 'id' not in o or o['id'] != uid ): - o['password'] = '********' - return o - 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, long)): - result = override_password(result) - else: - result = map(override_password, result) - return result - - def _check_company(self, cr, uid, ids, context=None): return all(((this.company_id in this.company_ids) or not this.company_ids) for this in self.browse(cr, uid, ids, context)) @@ -276,8 +261,34 @@ class res_users(osv.osv): return self.pool.get('res.partner').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'] + # User can write to a few of its own fields (but not her groups for example) + SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz'] + # user can read a few of its own fields + SELF_READABLE_FIELDS = ['signature', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id'] + + def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): + def override_password(o): + if 'password' in o and ('id' not in o or o['id'] != uid): + o['password'] = '********' + return o + + if (isinstance(ids, (list, tuple)) and ids == [uid]) or ids == uid: + for key in fields: + if not (key in self.SELF_READABLE_FIELDS or key.startswith('context_') or key in ['__last_update']): + break + else: + # safe fields only, so we read as super-user to bypass access rights + uid = 1 + + result = super(res_users, self).read(cr, uid, ids, fields=fields, context=context, load=load) + canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False) + if not canwrite: + if isinstance(ids, (int, long)): + result = override_password(result) + else: + result = map(override_password, result) + + return result def write(self, cr, uid, ids, values, context=None): if not hasattr(ids, '__iter__'): diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index 877e804314c..f8d51ce0fa8 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -120,6 +120,7 @@ class object_proxy(object): raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.') return f(self, dbname, *args, **kwargs) except orm.except_orm, inst: + raise raise except_osv(inst.name, inst.value) except except_osv: raise From c7ee41cfbb98a07cc6549338601ccf4e08ba5922 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Tue, 18 Sep 2012 13:57:17 +0200 Subject: [PATCH 2/9] [FIX] wording in comments bzr revid: abo@openerp.com-20120918115717-p57dpbdpbht1m4wr --- openerp/addons/base/res/res_users.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 1b167ff5077..7d68d0a5726 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -52,7 +52,7 @@ class groups(osv.osv): else: res[g.id] = g.name return res - + def _search_group(self, cr, uid, obj, name, args, context=None): operand = args[0][2] operator = args[0][1] @@ -64,7 +64,7 @@ class groups(osv.osv): group_name = values[1] where = ['|',('category_id.name', operator, application_name)] + where return where - + _columns = { 'name': fields.char('Name', size=64, required=True, translate=True), 'users': fields.many2many('res.users', 'res_groups_users_rel', 'gid', 'uid', 'Users'), @@ -138,7 +138,7 @@ class res_users(osv.osv): def _get_password(self, cr, uid, ids, arg, karg, context=None): return dict.fromkeys(ids, '') - + _columns = { 'id': fields.integer('ID'), 'login_date': fields.date('Latest connection', select=1), @@ -261,9 +261,9 @@ class res_users(osv.osv): return self.pool.get('res.partner').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 its own fields (but not her groups for example) + # User can write on a few of his own fields (but not his groups for example) SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz'] - # user can read a few of its own fields + # User can read a few of his own fields SELF_READABLE_FIELDS = ['signature', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id'] def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): @@ -506,14 +506,14 @@ class res_users(osv.osv): """ assert group_ext_id and '.' in group_ext_id, "External ID must be fully qualified" module, ext_id = group_ext_id.split('.') - cr.execute("""SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN + cr.execute("""SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN (SELECT res_id FROM ir_model_data WHERE module=%s AND name=%s)""", (uid, module, ext_id)) return bool(cr.fetchone()) # -# Extension of res.groups and res.users with a relation for "implied" or +# Extension of res.groups and res.users with a relation for "implied" or # "inherited" groups. Once a user belongs to a group, it automatically belongs # to the implied groups (transitively). # From d63b7de7cced46aedcc1142fafc6911168ee76aa Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Tue, 18 Sep 2012 14:02:30 +0200 Subject: [PATCH 3/9] [IMP] use const SUPERUSER_ID instead of int 1 bzr revid: abo@openerp.com-20120918120230-h8b1qtaiev5jbpwr --- openerp/addons/base/res/res_users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 7d68d0a5726..439ed1258ac 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -278,7 +278,7 @@ class res_users(osv.osv): break else: # safe fields only, so we read as super-user to bypass access rights - uid = 1 + uid = SUPERUSER_ID result = super(res_users, self).read(cr, uid, ids, fields=fields, context=context, load=load) canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', False) From 8353cc1ca909dd1e31729cd5af11e1752f4f5f81 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Tue, 18 Sep 2012 16:14:21 +0200 Subject: [PATCH 4/9] [FIX] res_partner.py: read countries as SUPERUSER res_users.py: add login to the readable fields bzr revid: abo@openerp.com-20120918141421-k6awa3xf6x2nx691 --- openerp/addons/base/res/res_partner.py | 7 ++++--- openerp/addons/base/res/res_users.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 008e8048a5d..6f793012b29 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -22,6 +22,7 @@ import math import openerp from osv import osv, fields +from openerp import SUPERUSER_ID import re import tools from tools.translate import _ @@ -33,7 +34,7 @@ from lxml import etree class format_address(object): def fields_view_get_address(self, cr, uid, arch, context={}): user_obj = self.pool.get('res.users') - fmt = user_obj.browse(cr, uid, uid,context).company_id.country_id + fmt = user_obj.browse(cr, SUPERUSER_ID, uid, context).company_id.country_id fmt = fmt and fmt.address_format layouts = { '%(city)s %(state_code)s\n%(zip)s': """ @@ -392,7 +393,7 @@ class res_partner(osv.osv, format_address): - otherwise: default, everything is set as the name """ match = re.search(r'([^\s,<@]+@[^>\s,]+)', text) if match: - email = match.group(1) + email = match.group(1) name = text[:text.index(email)].replace('"','').replace('<','').strip() else: name, email = text, '' @@ -440,7 +441,7 @@ class res_partner(osv.osv, format_address): def find_or_create(self, cr, uid, email, context=None): """ Find a partner with the given ``email`` or use :py:method:`~.name_create` to create one - + :param str email: email-like string, which should contain at least one email, e.g. ``"Raoul Grosbedon "``""" assert email, 'an email is required for find_or_create to work' diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 439ed1258ac..3b05cc74ff2 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -264,7 +264,7 @@ class res_users(osv.osv): # User can write on a few of his own fields (but not his groups for example) SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz'] # User can read a few of his own fields - SELF_READABLE_FIELDS = ['signature', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id'] + SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id'] def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): def override_password(o): From ae87c376689522d166709bdd6e4101a47370a9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 19 Sep 2012 10:23:28 +0200 Subject: [PATCH 5/9] [COM] commented a modif. bzr revid: tde@openerp.com-20120919082328-ljo621cftf8csnjh --- openerp/osv/osv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index d59998193a2..94703903e6d 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -121,7 +121,8 @@ class object_proxy(object): return f(self, dbname, *args, **kwargs) except orm.except_orm, inst: raise - raise except_osv(inst.name, inst.value) + # TDE: commented to have more valuable stack traces + # raise except_osv(inst.name, inst.value) except except_osv: raise except IntegrityError, inst: From 0d428b2b72b4c57a578f32039cb023a943a820c6 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Wed, 19 Sep 2012 13:48:44 +0200 Subject: [PATCH 6/9] [FIX] read user data through a read() instead of a browse() this way, we prevent the auto-loading of all the user's fields which crashes the contact form when it's submitted by a portal user bzr revid: abo@openerp.com-20120919114844-zhbgxkyoufz7ac2m --- openerp/addons/base/res/res_company.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index b27476b2c92..f4cebd12ae6 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -195,11 +195,11 @@ class res_company(osv.osv): ] ids = proxy.search(cr, uid, args, context=context) - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + user = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context)[0] for rule in proxy.browse(cr, uid, ids, context): if eval(rule.expression, {'context': context, 'user': user}): return rule.company_dest_id.id - return user.company_id.id + return user['company_id'][0] @tools.ormcache() def _get_company_children(self, cr, uid=None, company=None): From adf470bc886bb04686f89f7eb24231a9029d93f4 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Fri, 28 Sep 2012 18:39:56 +0200 Subject: [PATCH 7/9] [FIX] some security issues bzr revid: abo@openerp.com-20120928163956-3qytfhh1t03xaa1x --- openerp/addons/base/res/res_company.py | 4 ++-- openerp/addons/base/res/res_users.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index f4cebd12ae6..e0f82c51da3 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -195,11 +195,11 @@ class res_company(osv.osv): ] ids = proxy.search(cr, uid, args, context=context) - user = self.pool.get('res.users').read(cr, uid, [uid], ['company_id'], context=context)[0] + user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, [uid], ['company_id'], context=context)[0] for rule in proxy.browse(cr, uid, ids, context): if eval(rule.expression, {'context': context, 'user': user}): return rule.company_dest_id.id - return user['company_id'][0] + return user.company_id.id @tools.ormcache() def _get_company_children(self, cr, uid=None, company=None): diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 3b05cc74ff2..8bd5c3a0179 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -264,7 +264,7 @@ class res_users(osv.osv): # User can write on a few of his own fields (but not his groups for example) SELF_WRITEABLE_FIELDS = ['password', 'signature', 'action_id', 'company_id', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz'] # User can read a few of his own fields - SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id'] + SELF_READABLE_FIELDS = ['signature', 'company_id', 'login', 'email', 'name', 'image', 'image_medium', 'image_small', 'lang', 'tz', 'groups_id', 'partner_id', '__last_update'] def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): def override_password(o): @@ -272,9 +272,9 @@ class res_users(osv.osv): o['password'] = '********' return o - if (isinstance(ids, (list, tuple)) and ids == [uid]) or ids == uid: + if fields and (ids == [uid] or ids == uid): for key in fields: - if not (key in self.SELF_READABLE_FIELDS or key.startswith('context_') or key in ['__last_update']): + if not (key in self.SELF_READABLE_FIELDS or key.startswith('context_')): break else: # safe fields only, so we read as super-user to bypass access rights From 1a9f83c63fcbba2b54946168c08cacd147b05877 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Fri, 28 Sep 2012 18:52:39 +0200 Subject: [PATCH 8/9] [IMP] code style; also remove a debug comment bzr revid: abo@openerp.com-20120928165239-04lcfyt1t9ffdhkk --- openerp/addons/base/res/res_company.py | 2 +- openerp/osv/osv.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index e0f82c51da3..1613d954171 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -195,7 +195,7 @@ class res_company(osv.osv): ] ids = proxy.search(cr, uid, args, context=context) - user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, [uid], ['company_id'], context=context)[0] + user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, ['company_id'], context=context) for rule in proxy.browse(cr, uid, ids, context): if eval(rule.expression, {'context': context, 'user': user}): return rule.company_dest_id.id diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index 94703903e6d..94f179c7897 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -120,9 +120,7 @@ class object_proxy(object): raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.') return f(self, dbname, *args, **kwargs) except orm.except_orm, inst: - raise - # TDE: commented to have more valuable stack traces - # raise except_osv(inst.name, inst.value) + raise except_osv(inst.name, inst.value) except except_osv: raise except IntegrityError, inst: From ad2d32b2f8c84d5a6acbb9be935fa7a0ef31bba4 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Fri, 28 Sep 2012 19:11:39 +0200 Subject: [PATCH 9/9] [FIX] forgot to remove a field bzr revid: abo@openerp.com-20120928171139-v9m5a2rahqnhd8t1 --- openerp/addons/base/res/res_company.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 1613d954171..5095cc8b1a4 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -195,7 +195,7 @@ class res_company(osv.osv): ] ids = proxy.search(cr, uid, args, context=context) - user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, ['company_id'], context=context) + user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) for rule in proxy.browse(cr, uid, ids, context): if eval(rule.expression, {'context': context, 'user': user}): return rule.company_dest_id.id