diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 65d97d0b..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,4 +0,0 @@ -# These are supported funding model platforms - -patreon: dr_dimitru -custom: https://paypal.me/veliovgroup diff --git a/.npm/package/npm-shrinkwrap.json b/.npm/package/npm-shrinkwrap.json index 840e7661..57015146 100644 --- a/.npm/package/npm-shrinkwrap.json +++ b/.npm/package/npm-shrinkwrap.json @@ -67,9 +67,9 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=" }, "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" }, "extend": { "version": "3.0.2", @@ -92,9 +92,9 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "file-type": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-11.1.0.tgz", - "integrity": "sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==" + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.0.0.tgz", + "integrity": "sha512-VV3aQAyoV/fHl0I9uU3/DGjItgh5nylAoJPHOXkZXHW4nFFrxJnHR2xdVqsqyw/9fqYy80m+tS+Rf77w0FTKqg==" }, "forever-agent": { "version": "0.6.1", @@ -107,9 +107,9 @@ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==" }, "fs-extra": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", - "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==" + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==" }, "getpass": { "version": "0.1.7", @@ -117,9 +117,9 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=" }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" }, "har-schema": { "version": "2.0.0", @@ -197,9 +197,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz", + "integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==" }, "punycode": { "version": "2.1.1", diff --git a/.versions b/.versions index 597f5b2f..8286b645 100644 --- a/.versions +++ b/.versions @@ -22,7 +22,7 @@ geojson-utils@1.0.10 http@1.4.2 id-map@1.1.0 inter-process-messaging@0.1.0 -local-test:ostrio:files@1.11.1 +local-test:ostrio:files@1.11.2 logging@1.1.20 meteor@1.9.3 minimongo@1.4.5 @@ -36,7 +36,7 @@ mongo-id@1.0.7 npm-mongo@3.1.2 ordered-dict@1.1.0 ostrio:cookies@2.3.0 -ostrio:files@1.11.1 +ostrio:files@1.11.2 promise@0.11.2 random@1.1.0 reactive-var@1.0.11 diff --git a/docs/google-cloud-storage-integration.md b/docs/google-cloud-storage-integration.md index ce4f6c77..d82cd2a7 100644 --- a/docs/google-cloud-storage-integration.md +++ b/docs/google-cloud-storage-integration.md @@ -1,47 +1,57 @@ -#### Using Google Cloud Storage as your storage provider +# Using Google Cloud Storage as your storage provider + This example shows how to add and retrieve files using Google Cloud Storage. Additionally, this example will also show you how to list uploaded files and remove any of them. *See production-ready code below.* -##### Step 1: install [google-cloud-node](https://github.com/GoogleCloudPlatform/google-cloud-node) +## Prerequisite + +We will use next packages: *Request* (NPM), *Random* (meteor), *Underscore* (meteor) ```shell -npm install --save google-cloud +meteor add underscore +meteor add random +meteor npm install request ``` -Or + +### Step 1: install [google-cloud-storage](https://github.com/googleapis/nodejs-storage) + ```shell -meteor npm install google-cloud +npm install @google-cloud/storage" ``` -##### Step 2: Setup your Google Cloud Storage -- Sign into the Google Cloud Console site: https://console.developers.google.com +### Step 2: Setup your Google Cloud Storage + +- Sign into the [Google Cloud Console site](https://console.developers.google.com) - Go to your project and under Storage click on Create Bucket, and name your Bucket - * Don't forget the name of this bucket, you'll need it later + - Don't forget the name of this bucket, you'll need it later - Under APIs & Auth click on Credentials - Create an OAuth Service Account for your project (*if you don't already have one*) - If you do not have a private key, click "*Generate new key*" - * This will download a JSON file to your computer - * Keep this JSON file, it is your key to the account, and you will need it later - * Also, __GUARD THIS JSON FILE AS YOUR LIFE__. IF ANYONE GETS AHOLD OF IT, THEY WILL HAVE FULL ACCESS TO YOUR ACCOUNT! + - This will download a JSON file to your computer + - Keep this JSON file, it is your key to the account, and you will need it later + - Also, __GUARD THIS JSON FILE AS YOUR LIFE__. IF ANYONE GETS AHOLD OF IT, THEY WILL HAVE FULL ACCESS TO YOUR ACCOUNT! -```javascript -var gcloud, gcs, bucket, bucketMetadata, Request, bound, Collections = {}; +```js +let gcloud, gcs, bucket, bucketMetadata, Request, bound, Collections = {}; if (Meteor.isServer) { - gcloud = Npm.require('google-cloud')({ + // use require() as "'import' and 'export' may only appear at the top level" + const Random = require('meteor/random'); + const Storage = require('@google-cloud/storage'); + gcs = new Storage('google-cloud')({ projectId: 'YOUR_PROJECT_ID', // <-- Replace this with your project ID keyFilename: 'YOUR_KEY_JSON' // <-- Replace this with the path to your key.json }); - gcs = gcloud.storage(); bucket = gcs.bucket('YOUR_BUCKET_NAME'); // <-- Replace this with your bucket name - bucket.getMetadata(function(error, metadata, apiResponse){ + bucket.getMetadata(function(error, metadata, apiResponse) { if (error) { console.error(error); } }); Request = Npm.require('request'); - bound = Meteor.bindEnvironment(function(callback){ + bound = Meteor.bindEnvironment(function(callback) { return callback(); }); } @@ -51,41 +61,40 @@ Collections.files = new FilesCollection({ storagePath: 'assets/app/uploads/uploadedFiles', collectionName: 'uploadedFiles', allowClientCode: false, - onAfterUpload: function(fileRef) { + onAfterUpload(fileRef) { // In the onAfterUpload callback, we will move the file to Google Cloud Storage - var self = this; - _.each(fileRef.versions, function(vRef, version){ + _.each(fileRef.versions, (vRef, version) => { // We use Random.id() instead of real file's _id // to secure files from reverse engineering // As after viewing this code it will be easy // to get access to unlisted and protected files - var filePath = "files/" + (Random.id()) + "-" + version + "." + fileRef.extension; + const filePath = 'files/' + (Random.id()) + '-' + version + '.' + fileRef.extension; // Here we set the neccesary options to upload the file, for more options, see // https://googlecloudplatform.github.io/gcloud-node/#/docs/v0.36.0/storage/bucket?method=upload - var options = { + const options = { destination: filePath, resumable: true }; - bucket.upload(fileRef.path, options, function(error, file){ - bound(function(){ - var upd; + bucket.upload(fileRef.path, options, (error, file) => { + bound(() => { + let upd; if (error) { console.error(error); } else { upd = { $set: {} }; - upd['$set']["versions." + version + ".meta.pipePath"] = filePath; - self.collection.update({ + upd['$set'][`versions.${version}.meta.pipePath`] = filePath; + this.collection.update({ _id: fileRef._id - }, upd, function (error) { - if (error) { - console.error(error); + }, upd, (updError) => { + if (updError) { + console.error(updError); } else { // Unlink original files from FS // after successful upload to Google Cloud Storage - self.unlink(self.collection.findOne(fileRef._id), version); + this.unlink(this.collection.findOne(fileRef._id), version); } }); } @@ -93,36 +102,35 @@ Collections.files = new FilesCollection({ }); }); }, - interceptDownload: function(http, fileRef, version) { - var path, ref, ref1, ref2; - path = (ref= fileRef.versions) != null ? (ref1 = ref[version]) != null ? (ref2 = ref1.meta) != null ? ref2.pipePath : void 0 : void 0 : void 0; - var vRef = ref1; + interceptDownload(http, fileRef, version) { + let ref, ref1, ref2; + const path = (ref= fileRef.versions) != null ? (ref1 = ref[version]) != null ? (ref2 = ref1.meta) != null ? ref2.pipePath : void 0 : void 0 : void 0; + const vRef = ref1; if (path) { // If file is moved to Google Cloud Storage // We will pipe request to Google Cloud Storage // So, original link will stay always secure - var remoteReadStream = getReadableStream(http, path, vRef); + const remoteReadStream = getReadableStream(http, path, vRef); this.serve(http, fileRef, vRef, version, remoteReadStream); return true; - } else { - // While the file has not been uploaded to Google Cloud Storage, we will serve it from the filesystem - return false; } + // While the file has not been uploaded to Google Cloud Storage, we will serve it from the filesystem + return false; } }); if (Meteor.isServer) { // Intercept file's collection remove method to remove file from Google Cloud Storage - var _origRemove = Collections.files.remove; + const _origRemove = Collections.files.remove; Collections.files.remove = function(search) { - var cursor = this.collection.find(search); - cursor.forEach(function(fileRef) { - _.each(fileRef.versions, function(vRef) { - var ref; + const cursor = this.collection.find(search); + cursor.forEach((fileRef) => { + _.each(fileRef.versions, (vRef) => { + let ref; if (vRef != null ? (ref = vRef.meta) != null ? ref.pipePath : void 0 : void 0) { - bucket.file(vRef.meta.pipePath).delete(function(error) { - bound(function() { + bucket.file(vRef.meta.pipePath).delete((error) => { + bound(() => { if (error) { console.error(error); } @@ -137,7 +145,7 @@ if (Meteor.isServer) { } function getReadableStream(http, path, vRef){ - var array, end, partial, remoteReadStream, reqRange, responseType, start, take; + let array, end, partial, remoteReadStream, reqRange, responseType, start, take; if (http.request.headers.range) { partial = true; @@ -179,12 +187,12 @@ function getReadableStream(http, path, vRef){ responseType = '200'; } - if (responseType === "206") { + if (responseType === '206') { remoteReadStream = bucket.file(path).createReadStream({ start: reqRange.start, end: reqRange.end }); - } else if (responseType === "200") { + } else if (responseType === '200') { remoteReadStream = bucket.file(path).createReadStream(); } diff --git a/package.js b/package.js index c6fe2303..e8604874 100755 --- a/package.js +++ b/package.js @@ -1,16 +1,16 @@ Package.describe({ name: 'ostrio:files', - version: '1.11.1', + version: '1.11.2', summary: 'Upload files to Meteor application, with 3rd party storage support: AWS:S3, GridFS and other', git: 'https://github.com/VeliovGroup/Meteor-Files', documentation: 'README.md' }); Npm.depends({ - 'fs-extra': '8.0.1', + 'fs-extra': '8.1.0', request: '2.88.0', 'file-type': '12.0.0', - eventemitter3: '3.1.2' + eventemitter3: '4.0.0' }); Package.onUse(function(api) {