diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/QValueFormatter.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/QValueFormatter.java index 0758dc44..1e824b59 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/QValueFormatter.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/QValueFormatter.java @@ -28,7 +28,6 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -468,7 +467,8 @@ public class QValueFormatter { for(QFieldMetaData field : table.getFields().values()) { - if(field.getType().equals(QFieldType.BLOB)) + Optional fileDownloadAdornment = field.getAdornment(AdornmentType.FILE_DOWNLOAD); + if(fileDownloadAdornment.isPresent()) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // file name comes from: // @@ -478,20 +478,7 @@ public class QValueFormatter // - tableLabel primaryKey fieldLabel // // - and - if the FILE_DOWNLOAD adornment had a DEFAULT_EXTENSION, then it gets added (preceded by a dot) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Optional fileDownloadAdornment = field.getAdornment(AdornmentType.FILE_DOWNLOAD); - Map adornmentValues = Collections.emptyMap(); - - if(fileDownloadAdornment.isPresent()) - { - adornmentValues = fileDownloadAdornment.get().getValues(); - } - else - { - /////////////////////////////////////////////////////// - // don't change blobs unless they are file-downloads // - /////////////////////////////////////////////////////// - continue; - } + Map adornmentValues = fileDownloadAdornment.get().getValues(); String fileNameField = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FIELD)); String fileNameFormat = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT)); @@ -542,7 +529,13 @@ public class QValueFormatter } } - record.setValue(field.getName(), "/data/" + table.getName() + "/" + primaryKey + "/" + field.getName() + "/" + fileName); + ///////////////////////////////////////////// + // if field type is blob, update its value // + ///////////////////////////////////////////// + if(QFieldType.BLOB.equals(field.getType())) + { + record.setValue(field.getName(), "/data/" + table.getName() + "/" + primaryKey + "/" + field.getName() + "/" + fileName); + } record.setDisplayValue(field.getName(), fileName); } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/storage/StorageInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/storage/StorageInput.java index 5407faeb..526c7c78 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/storage/StorageInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/storage/StorageInput.java @@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; public class StorageInput extends AbstractTableActionInput { private String reference; + private String contentType; @@ -74,4 +75,35 @@ public class StorageInput extends AbstractTableActionInput return (this); } + + + /******************************************************************************* + ** Getter for contentType + *******************************************************************************/ + public String getContentType() + { + return (this.contentType); + } + + + + /******************************************************************************* + ** Setter for contentType + *******************************************************************************/ + public void setContentType(String contentType) + { + this.contentType = contentType; + } + + + + /******************************************************************************* + ** Fluent setter for contentType + *******************************************************************************/ + public StorageInput withContentType(String contentType) + { + this.contentType = contentType; + return (this); + } + } diff --git a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/actions/S3StorageAction.java b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/actions/S3StorageAction.java index 96c72bde..bbffb63d 100644 --- a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/actions/S3StorageAction.java +++ b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/actions/S3StorageAction.java @@ -58,7 +58,7 @@ public class S3StorageAction extends AbstractS3Action implements QStorageInterfa AmazonS3 amazonS3 = getS3Utils().getAmazonS3(); String fullPath = getFullPath(storageInput); - S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(amazonS3, backend.getBucketName(), fullPath); + S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(amazonS3, backend.getBucketName(), fullPath, storageInput.getContentType()); return (s3UploadOutputStream); } catch(Exception e) diff --git a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStream.java b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStream.java index f67493ee..2edfbbc3 100644 --- a/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStream.java +++ b/qqq-backend-module-filesystem/src/main/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStream.java @@ -53,6 +53,7 @@ public class S3UploadOutputStream extends OutputStream private final AmazonS3 amazonS3; private final String bucketName; private final String key; + private final String contentType; private byte[] buffer = new byte[5 * 1024 * 1024]; private int offset = 0; @@ -68,11 +69,12 @@ public class S3UploadOutputStream extends OutputStream ** Constructor ** *******************************************************************************/ - public S3UploadOutputStream(AmazonS3 amazonS3, String bucketName, String key) + public S3UploadOutputStream(AmazonS3 amazonS3, String bucketName, String key, String contentType) { this.amazonS3 = amazonS3; this.bucketName = bucketName; this.key = key; + this.contentType = contentType; } @@ -96,6 +98,13 @@ public class S3UploadOutputStream extends OutputStream *******************************************************************************/ private void uploadIfNeeded() { + ObjectMetadata objectMetadata = null; + if(this.contentType != null) + { + objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(this.contentType); + } + if(offset == buffer.length) { ////////////////////////////////////////// @@ -104,7 +113,8 @@ public class S3UploadOutputStream extends OutputStream if(initiateMultipartUploadResult == null) { LOG.info("Initiating a multipart upload", logPair("key", key)); - initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, key)); + initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, key, objectMetadata)); + uploadPartResultList = new ArrayList<>(); } @@ -115,7 +125,8 @@ public class S3UploadOutputStream extends OutputStream .withInputStream(new ByteArrayInputStream(buffer)) .withBucketName(bucketName) .withKey(key) - .withPartSize(buffer.length); + .withPartSize(buffer.length) + .withObjectMetadata(objectMetadata); uploadPartResultList.add(amazonS3.uploadPart(uploadPartRequest)); @@ -166,6 +177,13 @@ public class S3UploadOutputStream extends OutputStream return; } + ObjectMetadata objectMetadata = null; + if(this.contentType != null) + { + objectMetadata = new ObjectMetadata(); + objectMetadata.setContentType(this.contentType); + } + if(initiateMultipartUploadResult != null) { if(offset > 0) @@ -180,7 +198,8 @@ public class S3UploadOutputStream extends OutputStream .withInputStream(new ByteArrayInputStream(buffer, 0, offset)) .withBucketName(bucketName) .withKey(key) - .withPartSize(offset); + .withPartSize(offset) + .withObjectMetadata(objectMetadata); uploadPartResultList.add(amazonS3.uploadPart(uploadPartRequest)); } @@ -193,8 +212,12 @@ public class S3UploadOutputStream extends OutputStream } else { + if(objectMetadata == null) + { + objectMetadata = new ObjectMetadata(); + } + LOG.info("Putting object (non-multipart)", logPair("key", key), logPair("length", offset)); - ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(offset); PutObjectResult putObjectResult = amazonS3.putObject(bucketName, key, new ByteArrayInputStream(buffer, 0, offset), objectMetadata); } diff --git a/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStreamTest.java b/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStreamTest.java index 96d43bce..dc0a15b0 100644 --- a/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStreamTest.java +++ b/qqq-backend-module-filesystem/src/test/java/com/kingsrook/qqq/backend/module/filesystem/s3/utils/S3UploadOutputStreamTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; /******************************************************************************* - ** Unit test for S3UploadOutputStream + ** Unit test for S3UploadOutputStream *******************************************************************************/ class S3UploadOutputStreamTest extends BaseS3Test { @@ -57,11 +57,11 @@ class S3UploadOutputStreamTest extends BaseS3Test outputStream.write("\n]\n".getBytes(StandardCharsets.UTF_8)); outputStream.close(); - S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(getS3Utils().getAmazonS3(), bucketName, key); + S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(getS3Utils().getAmazonS3(), bucketName, key, null); s3UploadOutputStream.write(outputStream.toByteArray(), 0, 5 * 1024 * 1024); s3UploadOutputStream.write(outputStream.toByteArray(), 0, 3 * 1024 * 1024); s3UploadOutputStream.write(outputStream.toByteArray(), 0, 3 * 1024 * 1024); s3UploadOutputStream.close(); } -} \ No newline at end of file +}