1313from contextlib import closing , contextmanager
1414from pathlib import Path
1515
16- import fsspec # pylint: disable=missing-manifest-dependency
16+ import fsspec
1717import psycopg2
18- from slugify import slugify # pylint: disable=missing-manifest-dependency
18+ from slugify import slugify
1919
2020import odoo
21- from odoo import _ , api , fields , models
21+ from odoo import api , fields , models
2222from odoo .exceptions import AccessError , UserError
23- from odoo .osv . expression import AND , OR , normalize_domain
23+ from odoo .fields import Domain
2424
2525from .strtobool import strtobool
2626
@@ -169,9 +169,9 @@ def _store_in_db_instead_of_object_storage_domain(self):
169169 for mimetype_key , limit in storage_config .items ():
170170 part = [("mimetype" , "=like" , f"{ mimetype_key } %" )]
171171 if limit :
172- part = AND ([part , [("file_size" , "<=" , limit )]])
172+ part = Domain . AND ([part , [("file_size" , "<=" , limit )]])
173173 # OR simplifies to [(1, '=', 1)] if a domain being OR'ed is empty
174- domain = OR ([domain , part ]) if domain else part
174+ domain = Domain . OR ([domain , part ]) if domain else part
175175 return domain
176176
177177 def _store_in_db_instead_of_object_storage (self , data , mimetype ):
@@ -224,22 +224,29 @@ def _store_in_db_instead_of_object_storage(self, data, mimetype):
224224 return False
225225
226226 def _get_datas_related_values (self , data , mimetype ):
227+ values = super (
228+ IrAttachment , self .with_context (mimetype = mimetype )
229+ )._get_datas_related_values (data , mimetype )
227230 storage = self .env .context .get ("storage_location" ) or self ._storage ()
228231 if data and storage in self ._get_storage_codes ():
229232 if self ._store_in_db_instead_of_object_storage (data , mimetype ):
230- # compute the fields that depend on datas
231- bin_data = data
232- values = {
233- "file_size" : len (bin_data ),
234- "checksum" : self ._compute_checksum (bin_data ),
235- "index_content" : self ._index (bin_data , mimetype ),
236- "store_fname" : False ,
237- "db_datas" : data ,
238- }
239- return values
240- return super (
241- IrAttachment , self .with_context (mimetype = mimetype )
242- )._get_datas_related_values (data , mimetype )
233+ # Force storing data in the database, overriding the filestore logic.
234+ values .update (
235+ {
236+ "store_fname" : False ,
237+ "db_datas" : data ,
238+ }
239+ )
240+ else :
241+ # Uses the full object storage path; standard Odoo uses a relative path.
242+ path = self ._get_fs_path (storage , data )
243+ values .update (
244+ {
245+ "store_fname" : f"{ storage } ://{ path } " ,
246+ "db_datas" : False ,
247+ }
248+ )
249+ return values
243250
244251 ###########################################################
245252 # Odoo methods that we override to use the object storage #
@@ -306,7 +313,7 @@ def write(self, vals):
306313 vals ["mimetype" ] = mimetypes [0 ]
307314 else :
308315 raise UserError (
309- _ (
316+ self . env . _ (
310317 "You can't write on multiple attachments with different "
311318 "mimetypes at the same time."
312319 )
@@ -697,9 +704,10 @@ def _move_attachment_to_store(self):
697704 self .ensure_one ()
698705 _logger .info ("inspecting attachment %s (%d)" , self .name , self .id )
699706 fname = self .store_fname
700- storage = fname .partition ("://" )[0 ]
701- if self ._is_storage_disabled (storage ):
702- fname = False
707+ if fname :
708+ storage = fname .partition ("://" )[0 ]
709+ if self ._is_storage_disabled (storage ):
710+ fname = False
703711 if fname :
704712 # migrating from filesystem filestore
705713 # or from the old 'store_fname' without the bucket name
@@ -723,7 +731,9 @@ def _move_attachment_to_store(self):
723731 @api .model
724732 def force_storage (self ):
725733 if not self .env ["res.users" ].browse (self .env .uid )._is_admin ():
726- raise AccessError (_ ("Only administrators can execute this action." ))
734+ raise AccessError (
735+ self .env ._ ("Only administrators can execute this action." )
736+ )
727737 location = self .env .context .get ("storage_location" ) or self ._storage ()
728738 if location not in self ._get_storage_codes ():
729739 return super ().force_storage ()
@@ -762,19 +772,22 @@ def force_storage_to_db_for_special_fields(
762772 )
763773 return
764774
765- domain = AND (
775+ domain = Domain . AND (
766776 (
767- normalize_domain (
777+ Domain . AND (
768778 [
769- ("store_fname" , "=like" , f"{ storage } ://%" ),
779+ Domain ("store_fname" , "=like" , f"{ storage } ://%" ),
770780 # for res_field, see comment in
771781 # _force_storage_to_object_storage
772- "|" ,
773- ("res_field" , "=" , False ),
774- ("res_field" , "!=" , False ),
782+ Domain .OR (
783+ [
784+ Domain ("res_field" , "=" , False ),
785+ Domain ("res_field" , "!=" , False ),
786+ ]
787+ ),
775788 ]
776789 ),
777- normalize_domain (self ._store_in_db_instead_of_object_storage_domain ()),
790+ Domain (self ._store_in_db_instead_of_object_storage_domain ()),
778791 )
779792 )
780793
0 commit comments