119 """sql generator callback when some attribute with a custom storage is |
120 """sql generator callback when some attribute with a custom storage is |
120 accessed |
121 accessed |
121 """ |
122 """ |
122 fpath = source.binary_to_str(value) |
123 fpath = source.binary_to_str(value) |
123 try: |
124 try: |
124 return Binary(file(fpath, 'rb').read()) |
125 return Binary.from_file(fpath) |
125 except EnvironmentError, ex: |
126 except EnvironmentError, ex: |
126 source.critical("can't open %s: %s", value, ex) |
127 source.critical("can't open %s: %s", value, ex) |
127 return None |
128 return None |
128 |
129 |
129 def entity_added(self, entity, attr): |
130 def entity_added(self, entity, attr): |
130 """an entity using this storage for attr has been added""" |
131 """an entity using this storage for attr has been added""" |
131 if entity._cw.transaction_data.get('fs_importing'): |
132 if entity._cw.transaction_data.get('fs_importing'): |
132 binary = Binary(file(entity.cw_edited[attr].getvalue(), 'rb').read()) |
133 binary = Binary.from_file(entity.cw_edited[attr].getvalue()) |
133 else: |
134 else: |
134 binary = entity.cw_edited.pop(attr) |
135 binary = entity.cw_edited.pop(attr) |
135 fpath = self.new_fs_path(entity, attr) |
136 fpath = self.new_fs_path(entity, attr) |
136 # bytes storage used to store file's path |
137 # bytes storage used to store file's path |
137 entity.cw_edited.edited_attribute(attr, Binary(fpath)) |
138 entity.cw_edited.edited_attribute(attr, Binary(fpath)) |
138 file(fpath, 'wb').write(binary.getvalue()) |
139 binary.to_file(fpath) |
139 AddFileOp.get_instance(entity._cw).add_data(fpath) |
140 AddFileOp.get_instance(entity._cw).add_data(fpath) |
140 return binary |
141 return binary |
141 |
142 |
142 def entity_updated(self, entity, attr): |
143 def entity_updated(self, entity, attr): |
143 """an entity using this storage for attr has been updatded""" |
144 """an entity using this storage for attr has been updated""" |
144 # get the name of the previous file containing the value |
145 # get the name of the previous file containing the value |
145 oldpath = self.current_fs_path(entity, attr) |
146 oldpath = self.current_fs_path(entity, attr) |
146 if entity._cw.transaction_data.get('fs_importing'): |
147 if entity._cw.transaction_data.get('fs_importing'): |
147 # If we are importing from the filesystem, the file already exists. |
148 # If we are importing from the filesystem, the file already exists. |
148 # We do not need to create it but we need to fetch the content of |
149 # We do not need to create it but we need to fetch the content of |
149 # the file as the actual content of the attribute |
150 # the file as the actual content of the attribute |
150 fpath = entity.cw_edited[attr].getvalue() |
151 fpath = entity.cw_edited[attr].getvalue() |
151 assert fpath is not None |
152 assert fpath is not None |
152 binary = Binary(file(fpath, 'rb').read()) |
153 binary = Binary.from_file(fpath) |
153 else: |
154 else: |
154 # We must store the content of the attributes |
155 # We must store the content of the attributes |
155 # into a file to stay consistent with the behaviour of entity_add. |
156 # into a file to stay consistent with the behaviour of entity_add. |
156 # Moreover, the BytesFileSystemStorage expects to be able to |
157 # Moreover, the BytesFileSystemStorage expects to be able to |
157 # retrieve the current value of the attribute at anytime by reading |
158 # retrieve the current value of the attribute at anytime by reading |
166 else: |
167 else: |
167 # Get filename for it |
168 # Get filename for it |
168 fpath = self.new_fs_path(entity, attr) |
169 fpath = self.new_fs_path(entity, attr) |
169 assert not osp.exists(fpath) |
170 assert not osp.exists(fpath) |
170 # write attribute value on disk |
171 # write attribute value on disk |
171 file(fpath, 'wb').write(binary.getvalue()) |
172 binary.to_file(fpath) |
172 # Mark the new file as added during the transaction. |
173 # Mark the new file as added during the transaction. |
173 # The file will be removed on rollback |
174 # The file will be removed on rollback |
174 AddFileOp.get_instance(entity._cw).add_data(fpath) |
175 AddFileOp.get_instance(entity._cw).add_data(fpath) |
175 if oldpath != fpath: |
176 if oldpath != fpath: |
176 # register the new location for the file. |
177 # register the new location for the file. |
206 self.default_directory, '_'.join(basename)) |
207 self.default_directory, '_'.join(basename)) |
207 raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg}) |
208 raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg}) |
208 return fspath |
209 return fspath |
209 |
210 |
210 def current_fs_path(self, entity, attr): |
211 def current_fs_path(self, entity, attr): |
211 """return the current fs_path of the tribute. |
212 """return the current fs_path of the attribute, or None is the attr is |
212 |
213 not stored yet. |
213 Return None is the attr is not stored yet.""" |
214 """ |
214 sysource = entity._cw.cnxset.source('system') |
215 sysource = entity._cw.cnxset.source('system') |
215 cu = sysource.doexec(entity._cw, |
216 cu = sysource.doexec(entity._cw, |
216 'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s' % ( |
217 'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s' % ( |
217 attr, entity.__regid__, entity.eid)) |
218 attr, entity.__regid__, entity.eid)) |
218 rawvalue = cu.fetchone()[0] |
219 rawvalue = cu.fetchone()[0] |