server/sources/storages.py
branchstable
changeset 5219 35d44017c72b
parent 5218 aebd00a2d316
child 5396 78d92a47a4e5
child 5421 8167de96c523
equal deleted inserted replaced
5218:aebd00a2d316 5219:35d44017c72b
    72             return path
    72             return path
    73     return None
    73     return None
    74 
    74 
    75 class BytesFileSystemStorage(Storage):
    75 class BytesFileSystemStorage(Storage):
    76     """store Bytes attribute value on the file system"""
    76     """store Bytes attribute value on the file system"""
    77     def __init__(self, defaultdir):
    77     def __init__(self, defaultdir, fsencoding='utf-8'):
    78         self.default_directory = defaultdir
    78         self.default_directory = defaultdir
       
    79         self.fsencoding = fsencoding
    79 
    80 
    80     def callback(self, source, value):
    81     def callback(self, source, value):
    81         """sql generator callback when some attribute with a custom storage is
    82         """sql generator callback when some attribute with a custom storage is
    82         accessed
    83         accessed
    83         """
    84         """
   118     def entity_deleted(self, entity, attr):
   119     def entity_deleted(self, entity, attr):
   119         """an entity using this storage for attr has been deleted"""
   120         """an entity using this storage for attr has been deleted"""
   120         DeleteFileOp(entity._cw, filepath=self.current_fs_path(entity, attr))
   121         DeleteFileOp(entity._cw, filepath=self.current_fs_path(entity, attr))
   121 
   122 
   122     def new_fs_path(self, entity, attr):
   123     def new_fs_path(self, entity, attr):
       
   124         # We try to get some hint about how to name the file using attribute's
       
   125         # name metadata, so we use the real file name and extension when
       
   126         # available. Keeping the extension is useful for example in the case of
       
   127         # PIL processing that use filename extension to detect content-type, as
       
   128         # well as providing more understandable file names on the fs.
   123         basename = [str(entity.eid), attr]
   129         basename = [str(entity.eid), attr]
   124         # We try to get some hint about how to name the file using attributes
       
   125         # metadata. Using the real file name and extension when available.
       
   126         #
       
   127         # Keeping the extension might be usefull for exemple in the case of PIL
       
   128         # processing that use filename extension to detect content-type.
       
   129         name = entity.attr_metadata(attr, 'name')
   130         name = entity.attr_metadata(attr, 'name')
   130         if name is not None:
   131         if name is not None:
   131             basename.append(name.encode(entity._cw.encoding))
   132             basename.append(name.encode(self.fsencoding))
   132         fspath = uniquify_path(self.default_directory, '_'.join(basename))
   133         fspath = uniquify_path(self.default_directory, '_'.join(basename))
   133         if fspath is None:
   134         if fspath is None:
   134             msg = entity._cw._('failed to uniquify path (%s, %s)') % (
   135             msg = entity._cw._('failed to uniquify path (%s, %s)') % (
   135                 dirpath, basename)
   136                 dirpath, '_'.join(basename))
   136             raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg})
   137             raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg})
   137         return fspath
   138         return fspath
   138 
   139 
   139     def current_fs_path(self, entity, attr):
   140     def current_fs_path(self, entity, attr):
   140         sysource = entity._cw.pool.source('system')
   141         sysource = entity._cw.pool.source('system')