[FIX] base: delete orphan translations without access right errors

Deleting an orphan translation is mostly impossible, since it requires
'write' access on the corresponding records, and checking access rights
fails because the records no longer exist!

Simply enable operations on orphan translations by ignoring the
corresponding records that do not exist.  And make sure that the patch
does not allow to create orphan translations.

closes odoo/odoo#86869

X-original-commit: 454aa2587dcda2582ae58650019669ff0e8baa2c
Signed-off-by: Raphael Collet <rco@odoo.com>
Co-authored-by: Martin Trigaux <mat@odoo.com>
This commit is contained in:
Raphael Collet
2022-03-22 08:47:54 +01:00
co-authored by Martin Trigaux
parent 3c520d70c6
commit c490f6fef0
2 changed files with 57 additions and 2 deletions
+5 -1
View File
@@ -521,9 +521,13 @@ class IrTranslation(models.Model):
# check for read/write access on translated field records
fmode = 'read' if mode == 'read' else 'write'
for mname, ids in model_ids.items():
records = self.env[mname].browse(ids)
records = self.env[mname].browse(ids).exists()
records.check_access_rights(fmode)
records.check_field_access_rights(fmode, model_fields[mname])
if mode == 'create' and set(records._ids) != set(ids):
raise ValidationError(_("Creating translation on non existing records"))
if not records:
continue
records.check_access_rule(fmode)
@api.constrains('type', 'name', 'value')
+52 -1
View File
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import AccessError, ValidationError
from odoo.tools import mute_logger
from odoo.tools.translate import quote, unquote, xml_translate, html_translate
from odoo.tests.common import TransactionCase, BaseCase
from odoo.tests.common import TransactionCase, BaseCase, new_test_user
from psycopg2 import IntegrityError
@@ -570,6 +571,56 @@ class TestTranslationWrite(TransactionCase):
"Did not fallback to source when reset"
)
def test_orphan(self):
""" What happens with orphan translations. """
self.env['res.lang']._activate_lang('fr_FR')
# create a user with access rights on partner categories
user = new_test_user(self.env, 'deleter')
group = self.env.ref('base.group_partner_manager')
user.groups_id = [(4, group.id)]
# this access rule triggers a MissingError
self.env['ir.rule'].create({
'model_id': self.env['ir.model']._get_id('res.partner.category'),
'groups': [(4, group.id)],
'domain_force': "[('name', 'ilike', 'e')]",
})
# create a translation, and delete the record from the database
translation = self.env['ir.translation'].create({
'type': 'model',
'name': 'res.partner.category,name',
'lang': 'fr_FR',
'res_id': self.category.id,
'src': 'Reblochon',
'value': 'Parfum Exquis',
'state': 'translated',
})
translation.flush()
translation.invalidate_cache()
self.cr.execute("DELETE FROM res_partner_category WHERE id=%s", [self.category.id])
# deleting the translation should be possible, provided the user has
# access rights on the translation's model
user0 = new_test_user(self.env, 'cannot modify category')
with self.assertRaises(AccessError):
translation.with_user(user0).unlink()
translation.with_user(user).unlink()
# however, creating orphan translations should not be possible
with self.assertRaises(ValidationError):
translation.with_user(user).create({
'type': 'model',
'name': 'res.partner.category,name',
'lang': 'fr_FR',
'res_id': self.category.id,
'src': 'Reblochon',
'value': 'Parfum Exquis',
'state': 'translated',
})
def test_field_selection(self):
""" Test translations of field selections. """
field = self.env['ir.model']._fields['state']