From adcdece693dae7a5204eb5304ebb38afd7b6a483 Mon Sep 17 00:00:00 2001 From: William Young Date: Thu, 14 Jul 2016 14:14:01 -0700 Subject: [PATCH 1/2] Add support for custom metadata Custom metadata can now be added to options by storing an object on the `metadata` key of options with the key:value pairs of metadata. The keys will automatically have 'x-awz-meta-' added to them, so they should just have the name wanted for the metadata without the aws specific prefix. --- src/Metadata.js | 19 +++++++++++++++++++ src/RNS3.js | 17 +++++++++++------ src/S3Policy.js | 12 ++++++++++-- 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/Metadata.js diff --git a/src/Metadata.js b/src/Metadata.js new file mode 100644 index 00000000..40a0de19 --- /dev/null +++ b/src/Metadata.js @@ -0,0 +1,19 @@ +/** + * Metadata + */ + +const metadataPrefix = 'x-amz-meta-'; // Lowercase due to aws requirements + +export class Metadata { + static generate(options) { + + let metadata = {}; + + if (options.metadata) { + Object.keys(options.metadata).forEach((k) => { metadata[metadataPrefix + k] = options.metadata[k] }); + } + + return metadata; + + } +} diff --git a/src/RNS3.js b/src/RNS3.js index ee79ee14..1eb61218 100644 --- a/src/RNS3.js +++ b/src/RNS3.js @@ -4,6 +4,7 @@ import { Request } from './Request'; import { S3Policy } from './S3Policy'; +import { Metadata } from './Metadata'; const EXPECTED_RESPONSE_KEY_VALUE_RE = { key: /(.*)<\/Key>/, @@ -29,17 +30,21 @@ export class RNS3 { static put(file, options) { options = Object.assign({}, options, { key: (options.keyPrefix || '') + file.name, - contentType: file.type + contentType: file.type, + metadata: Metadata.generate(options) }); let url = `https://${ options.bucket }.s3.amazonaws.com`; let method = "POST"; let policy = S3Policy.generate(options); - return Request.create(url, method, policy) - .set("file", file) - .send() - .then(setBodyAsParsedXML); - } + let request = Request.create(url, method, policy); + + Object.keys(options.metadata).forEach((k) => request.set(k, options.metadata[k])); + request.set('file', file); + + return request + .send() + .then(setBodyAsParsedXML); } } diff --git a/src/S3Policy.js b/src/S3Policy.js index ada1ef88..1de60cba 100644 --- a/src/S3Policy.js +++ b/src/S3Policy.js @@ -70,7 +70,8 @@ const getPolicyParams = (options) => { key: options.key, region: options.region, secretKey: options.secretKey, - successActionStatus: '' + (options.successActionStatus || DEFAULT_SUCCESS_ACTION_STATUS) + successActionStatus: '' + (options.successActionStatus || DEFAULT_SUCCESS_ACTION_STATUS), + metadata: options.metadata } } @@ -89,7 +90,7 @@ const formatPolicyForRequestBody = (base64EncodedPolicy, signature, options) => } const formatPolicyForEncoding = (policy) => { - return { + let policyForEncoding = { "expiration": policy.expiration, "conditions": [ {"bucket": policy.bucket}, @@ -102,6 +103,13 @@ const formatPolicyForEncoding = (policy) => { {"x-amz-date": policy.date.amzDate} ] } + + Object.keys(policy.metadata).forEach((k) => { + let metadata = String(policy.metadata[k]) + policyForEncoding.conditions.push({[k]: metadata}); + }) + + return policyForEncoding; } const getEncodedPolicy = (policy) => { From a606db458a6663e019d31c58a888a60fec4aabdd Mon Sep 17 00:00:00 2001 From: William Young Date: Thu, 14 Jul 2016 14:31:32 -0700 Subject: [PATCH 2/2] Update examples and documentation in readme The readme now documents the existance and usage of the options metadata field. --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 31111408..ec555b19 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,12 @@ let options = { region: "us-east-1", accessKey: "your-access-key", secretKey: "your-secret-key", - successActionStatus: 201 + successActionStatus: 201, + metadata: { + latitude: '123.506239', // Becomes x-amz-meta-latitude onec in S3 + longitude: '-23.045293', + photographer: 'John Doe' + } } RNS3.put(file, options).then(response => { @@ -91,6 +96,7 @@ Arguments: * `accessKey` **required** - Your S3 `AWSAccessKeyId` * `secretKey` **required** - Your S3 `AWSSecretKey` * `successActionStatus` - HTTP response status if successful, defaults to 201. + * `metadata` - Custom metadata to attach to your object Returns an object that behaves like a promise. It also has a `progress` method on it which accepts a callback and will invoke the callback with the upload progress.