diff --git a/cubicweb_s3storage/storages.py b/cubicweb_s3storage/storages.py index 8c41ae0c2e502caa74f688c92ebce846399b6f92_Y3ViaWN3ZWJfczNzdG9yYWdlL3N0b3JhZ2VzLnB5..3e07e7b1b10aee73b45581fe63dfd92d6c629d58_Y3ViaWN3ZWJfczNzdG9yYWdlL3N0b3JhZ2VzLnB5 100644 --- a/cubicweb_s3storage/storages.py +++ b/cubicweb_s3storage/storages.py @@ -86,4 +86,6 @@ self.entity_deleted(entity, attr) else: oldkey = self.get_s3_key(entity, attr) + if oldkey is not None: + oldkey, _ = self.parse_key(oldkey) key = self.new_s3_key(entity, attr) @@ -89,8 +91,4 @@ key = self.new_s3_key(entity, attr) - # save S3 key - entity.cw_edited.edited_attribute( - attr, Binary(key.encode('utf-8'))) - # copy Binary value, workaround for boto3 bug # https://github.com/boto/s3transfer/issues/80 # .read() is required since Binary can't wrap itself @@ -103,8 +101,8 @@ upload_key = key extra_args = self.get_upload_extra_args(entity, attr, key) - s3_object = self.bucket.put_object( - Body=buffer, - Key=upload_key, - **extra_args) + put_object_result = self.s3cnx.put_object(Body=buffer, + Bucket=self.bucket, + Key=upload_key, + **extra_args) buffer.close() @@ -110,4 +108,7 @@ buffer.close() + version_id = put_object_result.get('VersionId', None) + # save S3 key + entity = self.save_s3_key(entity, attr, upload_key, version_id) # when key is suffixed, move to final key in post commit event # remove temporary key on rollback @@ -133,7 +134,7 @@ def entity_deleted(self, entity, attr): """an entity using this storage for attr has been deleted""" - key = self.get_s3_key(entity, attr) + key, _ = self.parse_key(self.get_s3_key(entity, attr)) if key is None: # no key to remove return @@ -160,6 +161,31 @@ source.doexec(cnx, sql, attrs) entity.cw_edited = None + def save_s3_key(self, entity, attr, key, version_id=None): + """ + Save the s3 key into the entity bytes attribute + """ + id_string = key + if entity._cw.repo.config['s3-activate-object-versioning'] and \ + version_id is not None: + id_string = self.format_version_id_suffix(key, version_id) + entity.cw_edited.edited_attribute(attr, + Binary(id_string.encode('utf-8'))) + return entity + + def parse_key(self, key): + try: + key, version = key.rsplit(self.KEY_SEPARATOR, 1) + except ValueError: + return key, None + return key, version + + def format_version_id_suffix(self, key, version_id): + """ + Format the string that will store key and version id + """ + return f"{key}#{version_id}" + def get_s3_key(self, entity, attr): """ Return the S3 key of the S3 object storing the content of attribute