[FIX] upstream patch for base

This commit is contained in:
Parthiv Patel committed 2022-02-09 14:26:47 +00:00
1 parent b3b3296895
commit ace588a952
6 files changed
+62 -8

No files matched your search

+14 -2
View File
@@ -219,6 +219,18 @@ class AssetsBundle(object):
**self._get_asset_url_values(id=id, unique=unique, extra=extra, name=name, sep=sep, type=type)
)
def _unlink_attachments(self, attachments):
""" Unlinks attachments without actually calling unlink, so that the ORM cache is not cleared.
Specifically, if an attachment is generated while a view is rendered, clearing the ORM cache
could unload fields loaded with a sudo(), and expected to be readable by the view.
Such a view would be website.layout when main_object is an ir.ui.view.
"""
to_delete = set(attach.store_fname for attach in attachments if attach.store_fname)
self.env.cr.execute(f"DELETE FROM {attachments._table} WHERE id IN %s", [tuple(attachments.ids)])
for file_path in to_delete:
attachments._file_delete(file_path)
def clean_attachments(self, type):
""" Takes care of deleting any outdated ir.attachment records associated to a bundle before
saving a fresh one.
@@ -244,7 +256,7 @@ class AssetsBundle(object):
# avoid to invalidate cache if it's already empty (mainly useful for test)
if attachments:
attachments.unlink()
self._unlink_attachments(attachments)
# force bundle invalidation on other workers
self.env['ir.qweb'].clear_caches()
@@ -478,7 +490,7 @@ class AssetsBundle(object):
compiled = self.run_rtlcss(compiled)
if not self.css_errors and old_attachments:
old_attachments.unlink()
self._unlink_attachments(old_attachments)
old_attachments = None
fragments = self.rx_css_split.split(compiled)
+4 -1
View File
@@ -128,6 +128,7 @@ class IrAttachment(models.Model):
def _mark_for_gc(self, fname):
""" Add ``fname`` in a checklist for the filestore garbage collection. """
fname = re.sub('[.]', '', fname).strip('/\\')
# we use a spooldir: add an empty file in the subdirectory 'checklist'
full_path = os.path.join(self._full_path('checklist'), fname)
if not os.path.exists(full_path):
@@ -564,7 +565,9 @@ class IrAttachment(models.Model):
def copy(self, default=None):
self.check('write')
default = dict(default or {}, datas=self.datas)
if not (default or {}).keys() & {'datas', 'db_datas', 'raw'}:
# ensure the content is kept and recomputes checksum/store_fname
default = dict(default or {}, raw=self.raw)
return super(IrAttachment, self).copy(default)
def unlink(self):
+16 -1
View File
@@ -195,6 +195,9 @@ class IrMailServer(models.Model):
elif not host:
mail_server = self.sudo().search([], order='sequence', limit=1)
if not mail_server:
mail_server = self.env['ir.mail_server']
if mail_server:
smtp_server = mail_server.smtp_host
smtp_port = mail_server.smtp_port
@@ -243,7 +246,7 @@ class IrMailServer(models.Model):
local, at, domain = smtp_user.rpartition('@')
if at:
smtp_user = local + at + idna.encode(domain).decode('ascii')
connection.login(smtp_user, smtp_password or '')
mail_server._smtp_login(connection, smtp_user, smtp_password or '')
# Some methods of SMTP don't check whether EHLO/HELO was sent.
# Anyway, as it may have been sent by login(), all subsequent usages should consider this command as sent.
@@ -251,6 +254,18 @@ class IrMailServer(models.Model):
return connection
def _smtp_login(self, connection, smtp_user, smtp_password):
"""Authenticate the SMTP connection.
Can be overridden in other module for different authentication methods.Can be
called on the model itself or on a singleton.
:param connection: The SMTP connection to authenticate
:param smtp_user: The user to used for the authentication
:param smtp_password: The password to used for the authentication
"""
connection.login(smtp_user, smtp_password)
def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False,
attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None,
body_alternative=None, subtype_alternative='plain'):
+1 -2
View File
@@ -963,7 +963,6 @@ class Module(models.Model):
[('id', 'not in', excluded_category_ids)],
])
Module = self.env['ir.module.module']
records = self.env['ir.module.category'].search_read(domain, ['display_name'], order="sequence")
values_range = OrderedDict()
@@ -976,7 +975,7 @@ class Module(models.Model):
kwargs.get('filter_domain', []),
[('category_id', 'child_of', record_id), ('category_id', 'not in', excluded_category_ids)]
])
record['__count'] = Module.search_count(model_domain)
record['__count'] = self.env['ir.module.module'].search_count(model_domain)
values_range[record_id] = record
return {
+4
View File
@@ -999,6 +999,10 @@ class Users(models.Model):
return 'base/static/img/user-slash.png'
return super()._get_placeholder_filename(field=field)
def _mfa_type(self):
""" If an MFA method is enabled, returns its type as a string. """
return
def _mfa_url(self):
""" If an MFA method is enabled, returns the URL for its second step. """
return
@@ -24,11 +24,12 @@ class TestIrAttachment(TransactionCase):
# Blob1
self.blob1 = b'blob1'
self.blob1_b64 = base64.b64encode(self.blob1)
blob1_hash = hashlib.sha1(self.blob1).hexdigest()
self.blob1_fname = blob1_hash[:HASH_SPLIT] + '/' + blob1_hash
self.blob1_hash = hashlib.sha1(self.blob1).hexdigest()
self.blob1_fname = self.blob1_hash[:HASH_SPLIT] + '/' + self.blob1_hash
# Blob2
self.blob2 = b'blob2'
self.blob2_b64 = base64.b64encode(self.blob2)
def assertApproximately(self, value, expectedSize, delta=1):
# we don't used bin_size in context, because on write, the cached value is the data and not
@@ -239,3 +240,23 @@ class TestIrAttachment(TransactionCase):
self.env['ir.config_parameter'].set_param('base.image_autoresize_max_px', '0')
attach.raw = img_bin
self.assertApproximately(attach.raw, fullsize)
def test_11_copy(self):
"""
Copying an attachment preserves the data
"""
document = self.Attachment.create({'name': 'document', 'datas': self.blob2_b64})
document2 = document.copy({'name': "document (copy)"})
self.assertEqual(document2.name, "document (copy)")
self.assertEqual(document2.datas, document.datas)
self.assertEqual(document2.db_datas, document.db_datas)
self.assertEqual(document2.store_fname, document.store_fname)
self.assertEqual(document2.checksum, document.checksum)
document3 = document.copy({'datas': self.blob1_b64})
self.assertEqual(document3.datas, self.blob1_b64)
self.assertEqual(document3.raw, self.blob1)
self.assertTrue(self.filestore) # no data in db but has a store_fname
self.assertEqual(document3.db_datas, False)
self.assertEqual(document3.store_fname, self.blob1_fname)
self.assertEqual(document3.checksum, self.blob1_hash)