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') |