diff --git a/addons/anonymization/models/anonymization.py b/addons/anonymization/models/anonymization.py index 06ffcf92216..9819ba6b26e 100644 --- a/addons/anonymization/models/anonymization.py +++ b/addons/anonymization/models/anonymization.py @@ -59,11 +59,8 @@ class IrModelFieldsAnonymization(models.Model): @api.model def _get_model_and_field_ids(self, vals): if vals.get('field_name') and vals.get('model_name'): - model_id = self.env['ir.model'].search([('model', '=', vals['model_name'])], limit=1).id - if model_id: - field_id = self.env['ir.model.fields'].search([('name', '=', vals['field_name']), ('model_id', '=', model_id)], limit=1).id - if field_id: - return (model_id, field_id) + field = self.env['ir.model.fields']._get(vals['model_name'], vals['field_name']) + return (field.model_id.id, field.id) return (False, False) @api.model @@ -109,17 +106,12 @@ class IrModelFieldsAnonymization(models.Model): def _onchange_model_name(self): self.field_name = False self.field_id = False - if self.model_name: - self.model_id = self.env['ir.model'].search([('model', '=', self.model_name)], limit=1) - else: - self.model_id = False + self.model_id = self.env['ir.model']._get(self.model_name) @api.onchange('field_name') def _onchange_field_name(self): if self.field_name and self.model_name: - self.field_id = self.env['ir.model.fields'].search([ - ('name', '=', self.field_name), ('model', '=', self.model_name) - ], limit=1) + self.field_id = self.env['ir.model.fields']._get(self.model_name, self.field_name) else: self.field_id = False diff --git a/addons/mail/models/mail_alias.py b/addons/mail/models/mail_alias.py index eee18d10c5b..07d6bfb3d58 100644 --- a/addons/mail/models/mail_alias.py +++ b/addons/mail/models/mail_alias.py @@ -111,10 +111,10 @@ class Alias(models.Model): if vals.get('alias_name'): vals['alias_name'] = self._clean_and_make_unique(vals.get('alias_name')) if model_name: - model = self.env['ir.model'].search([('model', '=', model_name)]) + model = self.env['ir.model']._get(model_name) vals['alias_model_id'] = model.id if parent_model_name: - model = self.env['ir.model'].search([('model', '=', parent_model_name)]) + model = self.env['ir.model']._get(parent_model_name) vals['alias_parent_model_id'] = model.id return super(Alias, self).create(vals) diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py index 9187917643a..825053f4e36 100644 --- a/addons/mail/models/mail_followers.py +++ b/addons/mail/models/mail_followers.py @@ -40,7 +40,7 @@ class Followers(models.Model): :param force: if True, delete existing followers before creating new one using the subtypes given in the parameters """ - res_model_id = self.env['ir.model'].search([('model', '=', res_model)], limit=1).id + res_model_id = self.env['ir.model']._get(res_model).id force_mode = force or (all(data for data in partner_data.values()) and all(data for data in channel_data.values())) generic = [] specific = {} diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py index 527afc1c0cd..04d9fedde24 100644 --- a/addons/mail/models/mail_mail.py +++ b/addons/mail/models/mail_mail.py @@ -212,7 +212,7 @@ class MailMail(models.Model): try: # TDE note: remove me when model_id field is present on mail.message - done here to avoid doing it multiple times in the sub method if mail.model: - model = self.env['ir.model'].sudo().search([('model', '=', mail.model)])[0] + model = self.env['ir.model']._get(mail.model)[0] else: model = None if model: diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index a819c8d99a9..b4e66e71f33 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -106,7 +106,7 @@ class MailTemplate(models.Model): def default_get(self, fields): res = super(MailTemplate, self).default_get(fields) if res.get('model'): - res['model_id'] = self.env['ir.model'].search([('model', '=', res.pop('model'))]).id + res['model_id'] = self.env['ir.model']._get(res.pop('model')).id return res name = fields.Char('Name') @@ -201,9 +201,9 @@ class MailTemplate(models.Model): def onchange_sub_model_object_value_field(self): if self.model_object_field: if self.model_object_field.ttype in ['many2one', 'one2many', 'many2many']: - models = self.env['ir.model'].search([('model', '=', self.model_object_field.relation)]) - if models: - self.sub_object = models.id + model = self.env['ir.model']._get(self.model_object_field.relation) + if model: + self.sub_object = model.id self.copyvalue = self.build_expression(self.model_object_field.name, self.sub_model_object_field and self.sub_model_object_field.name or False, self.null_value or False) else: self.sub_object = False diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 14fdc651323..902f37bbb28 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -229,7 +229,7 @@ class MailThread(models.AbstractModel): # automatic logging unless asked not to (mainly for various testing purpose) if not self._context.get('mail_create_nolog'): - doc_name = self.env['ir.model'].search([('model', '=', self._name)]).read(['name'])[0]['name'] + doc_name = self.env['ir.model']._get(self._name).name thread.message_post(body=_('%s created') % doc_name) # auto_subscribe: take values and defaults into account @@ -663,7 +663,7 @@ class MailThread(models.AbstractModel): access_link = self._notification_link_helper('view', message_id=message.id) if message.model: - model_name = self.env['ir.model'].sudo().search([('model', '=', self.env[message.model]._name)]).name_get()[0][1] + model_name = self.env['ir.model']._get(message.model).display_name view_title = '%s %s' % (_('View'), model_name) else: view_title = _('View') @@ -1133,7 +1133,7 @@ class MailThread(models.AbstractModel): dest_aliases = Alias.search([('alias_name', 'in', rcpt_tos_localparts)]) if dest_aliases: routes = [] - for alias in dest_aliases: + for alias in dest_aliases.sudo(): user_id = alias.alias_user_id.id if not user_id: # TDE note: this could cause crashes, because no clue that the user diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index 3bdec9313db..ba927ac16ab 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -65,7 +65,7 @@ class Partner(models.Model): model_name = False if message.model: - model_name = self.env['ir.model'].sudo().search([('model', '=', self.env[message.model]._name)]).name_get()[0][1] + model_name = self.env['ir.model']._get(message.model).display_name record_name = message.record_name diff --git a/addons/mail/tests/test_mail_followers.py b/addons/mail/tests/test_mail_followers.py index c51978993bb..7a82f09f381 100644 --- a/addons/mail/tests/test_mail_followers.py +++ b/addons/mail/tests/test_mail_followers.py @@ -25,7 +25,7 @@ class TestMailFollowers(TestMail): 'mail.channel', groups.ids, {self.user_employee.partner_id.id: [self.mt_mg_nodef.id]}, {test_channel.id: [self.mt_al_nodef.id]}) - mail_channel_model_id = self.env['ir.model'].search([('model', '=', 'mail.channel')], limit=1).id + mail_channel_model_id = self.env['ir.model']._get('mail.channel').id self.assertFalse(specific) self.assertEqual(len(generic), 2) @@ -40,7 +40,7 @@ class TestMailFollowers(TestMail): def test_m2o_command_update_selective(self): test_channel = self.env['mail.channel'].create({'name': 'Test'}) - mail_channel_model_id = self.env['ir.model'].search([('model', '=', 'mail.channel')], limit=1).id + mail_channel_model_id = self.env['ir.model']._get('mail.channel').id groups = self.group_pigs | self.group_public self.env['mail.followers'].create({'partner_id': self.user_employee.partner_id.id, 'res_model_id': mail_channel_model_id, 'res_id': self.group_pigs.id}) generic, specific = self.env['mail.followers']._add_follower_command( @@ -136,7 +136,7 @@ class TestMailFollowers(TestMail): }) with self.assertRaises(IntegrityError): self.env['mail.followers'].create({ - 'res_model_id': self.env['ir.model'].search([('model', '=', 'mail.channel')], limit=1).id, + 'res_model_id': self.env['ir.model']._get('mail.channel').id, 'res_id': test_channel.id, 'partner_id': self.user_employee.partner_id.id, 'channel_id': self.group_pigs.id, diff --git a/addons/mail/tests/test_mail_gateway.py b/addons/mail/tests/test_mail_gateway.py index fd2f80ce103..c017a88df67 100644 --- a/addons/mail/tests/test_mail_gateway.py +++ b/addons/mail/tests/test_mail_gateway.py @@ -291,7 +291,7 @@ class TestMailgateway(TestMail): def setUp(self): super(TestMailgateway, self).setUp() # groups@.. will cause the creation of new mail.channels - self.mail_channel_model = self.env['ir.model'].search([('model', '=', 'mail.channel')], limit=1) + self.mail_channel_model = self.env['ir.model']._get('mail.channel') self.alias = self.env['mail.alias'].create({ 'alias_name': 'groups', 'alias_user_id': False, @@ -299,7 +299,7 @@ class TestMailgateway(TestMail): 'alias_contact': 'everyone'}) # test@.. will cause the creation of new mail.test - self.mail_test_model = self.env['ir.model'].search([('model', '=', 'mail.test')], limit=1) + self.mail_test_model = self.env['ir.model']._get('mail.test') self.alias_2 = self.env['mail.alias'].create({ 'alias_name': 'test', 'alias_user_id': False, diff --git a/addons/mail/tests/test_mail_template.py b/addons/mail/tests/test_mail_template.py index da335d741a4..26a0336b0fe 100644 --- a/addons/mail/tests/test_mail_template.py +++ b/addons/mail/tests/test_mail_template.py @@ -32,7 +32,7 @@ class TestMailTemplate(TestMail): self.email_2 = 'test2@example.com' self.email_3 = self.partner_1.email self.email_template = self.env['mail.template'].create({ - 'model_id': self.env['ir.model'].search([('model', '=', 'mail.channel')], limit=1).id, + 'model_id': self.env['ir.model']._get('mail.channel').id, 'name': 'Pigs Template', 'subject': '${object.name}', 'body_html': '${object.description}', diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index 1d345af517a..acb89641f75 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -18,7 +18,7 @@ class Invite(models.TransientModel): if self._context.get('mail_invite_follower_channel_only'): result['send_mail'] = False if 'message' in fields and model and res_id: - model_name = self.env['ir.model'].search([('model', '=', model)]).name_get()[0][1] + model_name = self.env['ir.model']._get(model).display_name document_name = self.env[model].browse(res_id).name_get()[0][1] message = _('

Hello,

%s invited you to follow %s document: %s.

') % (user_name, model_name, document_name) result['message'] = message @@ -46,8 +46,7 @@ class Invite(models.TransientModel): new_channels = wizard.channel_ids - document.message_channel_ids document.message_subscribe(new_partners.ids, new_channels.ids) - model_ids = self.env['ir.model'].search([('model', '=', wizard.res_model)]) - model_name = model_ids.name_get()[0][1] + model_name = self.env['ir.model']._get(wizard.res_model).display_name # send an email if option checked and if a message exists (do not send void emails) if wizard.send_mail and wizard.message and not wizard.message == '
': # when deleting the message, cleditor keeps a
message = self.env['mail.message'].create({ diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index bc27da14e7c..35114a2542b 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -392,16 +392,14 @@ class MailComposer(models.TransientModel): """ hit save as template button: current form value will be a new template attached to the current document. """ for record in self: - models = self.env['ir.model'].search([('model', '=', record.model or 'mail.message')]) - model_name = '' - if models: - model_name = models.name + model = self.env['ir.model']._get(record.model or 'mail.message') + model_name = model.name or '' template_name = "%s: %s" % (model_name, tools.ustr(record.subject)) values = { 'name': template_name, 'subject': record.subject or False, 'body_html': record.body or False, - 'model_id': models.id or False, + 'model_id': model.id or False, 'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])], } template = self.env['mail.template'].create(values) diff --git a/addons/marketing_campaign/models/ir_actions.py b/addons/marketing_campaign/models/ir_actions.py index cb9a55db6cc..8eaaa0ce69c 100644 --- a/addons/marketing_campaign/models/ir_actions.py +++ b/addons/marketing_campaign/models/ir_actions.py @@ -11,6 +11,6 @@ class IrActionsReportXml(models.Model): def search(self, args, offset=0, limit=None, order=None, count=False): model_id = self.env.context.get('object_id') if model_id: - model = self.env['ir.model'].browse(model_id).model + model = self.env['ir.model'].browse(model_id).sudo().model args.append(('model', '=', model)) return super(IrActionsReportXml, self).search(args, offset=offset, limit=limit, order=order, count=count) diff --git a/addons/marketing_campaign/models/marketing_campaign.py b/addons/marketing_campaign/models/marketing_campaign.py index 2aa745dfaa1..fc841868673 100644 --- a/addons/marketing_campaign/models/marketing_campaign.py +++ b/addons/marketing_campaign/models/marketing_campaign.py @@ -291,7 +291,7 @@ class MarketingCampaignActivity(models.Model): name = fields.Char('Name', required=True) campaign_id = fields.Many2one('marketing.campaign', 'Campaign', required=True, ondelete='cascade', index=True) - object_id = fields.Many2one(related='campaign_id.object_id', relation='ir.model', string='Object', readonly=True) + object_id = fields.Many2one('ir.model', related='campaign_id.object_id', string='Object', readonly=True) start = fields.Boolean('Start', help="This activity is launched when the campaign starts.", index=True) condition = fields.Text('Condition', required=True, default="True", help="Python expression to decide whether the activity can be executed, otherwise it will be deleted or cancelled." diff --git a/addons/project/models/project.py b/addons/project/models/project.py index f8213fff753..56b0035e025 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -257,9 +257,7 @@ class Project(models.Model): def write(self, vals): # if alias_model has been changed, update alias_model_id accordingly if vals.get('alias_model'): - vals['alias_model_id'] = self.env['ir.model'].search([ - ('model', '=', vals.get('alias_model', 'project.task')) - ], limit=1).id + vals['alias_model_id'] = self.env['ir.model']._get(vals.get('alias_model', 'project.task')).id res = super(Project, self).write(vals) if 'active' in vals: # archiving/unarchiving a project does it on its tasks, too diff --git a/addons/website_form/controllers/main.py b/addons/website_form/controllers/main.py index 742a8eeb0b7..2f5f7ec2292 100644 --- a/addons/website_form/controllers/main.py +++ b/addons/website_form/controllers/main.py @@ -21,7 +21,7 @@ class WebsiteForm(http.Controller): # Check and insert values from the form on the model @http.route('/website_form/', type='http', auth="public", methods=['POST'], website=True) def website_form(self, model_name, **kwargs): - model_record = request.env['ir.model'].search([('model', '=', model_name), ('website_form_access', '=', True)]) + model_record = request.env['ir.model'].sudo().search([('model', '=', model_name), ('website_form_access', '=', True)]) if not model_record: return json.dumps(False) diff --git a/addons/website_form/models/models.py b/addons/website_form/models/models.py index 16aba290a2a..f1a80abbb68 100644 --- a/addons/website_form/models/models.py +++ b/addons/website_form/models/models.py @@ -41,13 +41,14 @@ class website_form_model(models.Model): ]) } return { - k: v for k, v in self.get_authorized_fields().iteritems() + k: v for k, v in self.get_authorized_fields(self.model).iteritems() if k not in excluded } - @api.multi - def get_authorized_fields(self): - model = self.env[self.model] + @api.model + def get_authorized_fields(self, model_name): + """ Return the fields of the given model name as a mapping like method `fields_get`. """ + model = self.env[model_name] fields_get = model.fields_get() for key, val in model._inherits.iteritems(): diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index d8bff5d798b..3ec5d7f591e 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -507,7 +507,7 @@ class WebsiteSale(http.Controller): def values_postprocess(self, order, mode, values, errors, error_msg): new_values = {} - authorized_fields = request.env['ir.model'].sudo().search([('model', '=', 'res.partner')])._get_form_writable_fields() + authorized_fields = request.env['ir.model']._get('res.partner')._get_form_writable_fields() for k, v in values.items(): # don't drop empty value, it could be a field to reset if k in authorized_fields and v is not None: diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py index 868eba9b8bb..8d037a73097 100644 --- a/odoo/addons/base/ir/ir_model.py +++ b/odoo/addons/base/ir/ir_model.py @@ -103,6 +103,12 @@ class IrModel(models.Model): ('obj_name_uniq', 'unique (model)', 'Each model must be unique!'), ] + def _get(self, name): + """ Return the (sudoed) `ir.model` record with the given name. + The result may be an empty recordset if the model is not found. + """ + return self.sudo().search([('model', '=', name)]) + # overridden to allow searching both on model name (field 'model') and model # description (field 'name') @api.model @@ -848,18 +854,13 @@ class IrModelAccess(models.Model): # User root have all accesses return True + assert isinstance(model, basestring), 'Not a model name: %s' % (model,) assert mode in ('read', 'write', 'create', 'unlink'), 'Invalid access mode' - if isinstance(model, models.BaseModel): - assert model._name == 'ir.model', 'Invalid model object' - model_name = model.model - else: - model_name = model - # TransientModel records have no access rights, only an implicit access rule - if model_name not in self.env: - _logger.error('Missing model %s', model_name) - elif self.env[model_name].is_transient(): + if model not in self.env: + _logger.error('Missing model %s', model) + elif self.env[model].is_transient(): return True # We check if a specific rule exists @@ -870,7 +871,7 @@ class IrModelAccess(models.Model): WHERE m.model = %s AND gu.uid = %s AND a.active IS TRUE""".format(mode=mode), - (model_name, self._uid,)) + (model, self._uid,)) r = self._cr.fetchone()[0] if not r: @@ -881,11 +882,11 @@ class IrModelAccess(models.Model): WHERE a.group_id IS NULL AND m.model = %s AND a.active IS TRUE""".format(mode=mode), - (model_name,)) + (model,)) r = self._cr.fetchone()[0] if not r and raise_exception: - groups = '\n\t'.join('- %s' % g for g in self.group_names_with_access(model_name, mode)) + groups = '\n\t'.join('- %s' % g for g in self.group_names_with_access(model, mode)) msg_heads = { # Messages are declared in extenso so they are properly exported in translation terms 'read': _("Sorry, you are not allowed to access this document."), @@ -895,11 +896,11 @@ class IrModelAccess(models.Model): } if groups: msg_tail = _("Only users with the following access level are currently allowed to do that") + ":\n%s\n\n(" + _("Document model") + ": %s)" - msg_params = (groups, model_name) + msg_params = (groups, model) else: msg_tail = _("Please contact your system administrator if you think this is an error.") + "\n\n(" + _("Document model") + ": %s)" - msg_params = (model_name,) - _logger.info('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, self._uid, model_name) + msg_params = (model,) + _logger.info('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, self._uid, model) msg = '%s %s' % (msg_heads[mode], msg_tail) raise AccessError(msg % msg_params) diff --git a/odoo/addons/base/ir/ir_ui_menu.py b/odoo/addons/base/ir/ir_ui_menu.py index 08ac109d464..f37281e5773 100644 --- a/odoo/addons/base/ir/ir_ui_menu.py +++ b/odoo/addons/base/ir/ir_ui_menu.py @@ -109,15 +109,15 @@ class IrUiMenu(models.Model): # process action menus, check whether their action is allowed access = self.env['ir.model.access'] - model_fname = { - 'ir.actions.act_window': 'res_model', - 'ir.actions.report.xml': 'model', - 'ir.actions.server': 'model_id', + MODEL_GETTER = { + 'ir.actions.act_window': lambda action: action.res_model, + 'ir.actions.report.xml': lambda action: action.model, + 'ir.actions.server': lambda action: action.model_id.model, } - for menu in action_menus: - fname = model_fname.get(menu.action._name) - if not fname or not menu.action[fname] or \ - access.check(menu.action[fname], 'read', False): + for menu in action_menus.sudo(): + get_model = MODEL_GETTER.get(menu.action._name) + if not get_model or not get_model(menu.action) or \ + access.check(get_model(menu.action), 'read', False): # make menu visible, and its folder ancestors, too visible += menu menu = menu.parent_id diff --git a/odoo/addons/base/security/ir.model.access.csv b/odoo/addons/base/security/ir.model.access.csv index 4093c44391b..e60fce6af78 100644 --- a/odoo/addons/base/security/ir.model.access.csv +++ b/odoo/addons/base/security/ir.model.access.csv @@ -10,7 +10,6 @@ "access_ir_model_access_group_erp_manager","ir_model_access_group_erp_manager","model_ir_model_access","group_erp_manager",1,1,1,1 "access_ir_model_data_group_erp_manager","ir_model_data group_erp_manager","model_ir_model_data","group_erp_manager",1,1,1,1 "access_ir_model_fields_group_erp_manager","ir_model_fields group_erp_manager","model_ir_model_fields","group_erp_manager",1,1,1,1 -"access_ir_model_all","ir_model_all","model_ir_model",,1,0,0,0 "access_ir_model_constraint","ir_model_constraint","model_ir_model_constraint",,1,0,0,0 "access_ir_model_relation","ir_model_relation","model_ir_model_relation",,1,0,0,0 "access_ir_model_access_all","ir_model_access_all","model_ir_model_access",,1,0,0,0 diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py index 0d2054e32e5..8642bc60f74 100644 --- a/odoo/addons/test_new_api/models.py +++ b/odoo/addons/test_new_api/models.py @@ -227,7 +227,7 @@ class MixedModel(models.Model): @api.model def _reference_models(self): - models = self.env['ir.model'].search([('state', '!=', 'manual')]) + models = self.env['ir.model'].sudo().search([('state', '!=', 'manual')]) return [(model.model, model.name) for model in models if not model.model.startswith('ir.')] diff --git a/odoo/report/custom.py b/odoo/report/custom.py index be4b95f9389..e2fc352ad37 100644 --- a/odoo/report/custom.py +++ b/odoo/report/custom.py @@ -118,7 +118,7 @@ class report_custom(report_int): report = report.read()[0] fields = env['ir.report.custom.fields'].browse(report['fields_child0']).read() fields.sort(key=lambda x: x['sequence']) - model_name = env['ir.model'].browse(report['model_id'][0]).model + model_name = env['ir.model'].browse(report['model_id'][0]).sudo().model fct = { 'id': lambda x: x, diff --git a/odoo/report/printscreen/ps_list.py b/odoo/report/printscreen/ps_list.py index 23e6c09466d..5ef2ac83142 100644 --- a/odoo/report/printscreen/ps_list.py +++ b/odoo/report/printscreen/ps_list.py @@ -51,7 +51,7 @@ class report_printscreen_list(report_int): self.groupby_no_leaf = context.get('group_by_no_leaf', False) env = odoo.api.Environment(cr, uid, context) Model = env[datas['model']] - model = env['ir.model'].search([('model', '=', Model._name)]) + model = env['ir.model']._get(Model._name) model_desc = model.name or Model._description self.title = model_desc datas['ids'] = ids