From 52aecd0c8e0f8b4fd4bb84921213ff78000d6be6 Mon Sep 17 00:00:00 2001 From: Erik Kieckhafer Date: Wed, 31 Aug 2016 17:53:05 -0700 Subject: [PATCH] Release 0.15.2 (#1339) * Added babelrc and stage-2 preset (#1329) * Meteor 1.4.1.1 (#1331) * METEOR@1.4.1.1 - METEOR@1.4.1.1 - updated Meteor packages, collections2 * version 0.15.2 * move plugin loader from startup to reaction-cli (#1332) * preserve custom profile fields in Accounts.onCreateUser (#1335) * copy deprecated cfs:gridfs to local and update npm deps (#1336) --- .babelrc | 3 + .meteor/packages | 4 +- .meteor/release | 2 +- .meteor/versions | 16 +- package.json | 3 +- packages/gridfs/.npm/package/.gitignore | 1 + packages/gridfs/.npm/package/README | 7 + .../gridfs/.npm/package/npm-shrinkwrap.json | 89 +++++++++ packages/gridfs/.travis.yml | 5 + packages/gridfs/.versions | 29 +++ packages/gridfs/LICENSE.md | 20 ++ packages/gridfs/README.md | 48 +++++ packages/gridfs/api.md | 69 +++++++ packages/gridfs/gridfs.client.js | 21 +++ packages/gridfs/gridfs.server.js | 171 ++++++++++++++++++ packages/gridfs/internal.api.md | 75 ++++++++ packages/gridfs/package.js | 25 +++ packages/gridfs/tests/client-tests.js | 44 +++++ packages/gridfs/tests/server-tests.js | 49 +++++ server/startup/accounts.js | 2 +- server/startup/index.js | 2 - server/startup/plugins.js | 160 ---------------- 22 files changed, 670 insertions(+), 175 deletions(-) create mode 100644 .babelrc create mode 100644 packages/gridfs/.npm/package/.gitignore create mode 100644 packages/gridfs/.npm/package/README create mode 100644 packages/gridfs/.npm/package/npm-shrinkwrap.json create mode 100755 packages/gridfs/.travis.yml create mode 100755 packages/gridfs/.versions create mode 100755 packages/gridfs/LICENSE.md create mode 100755 packages/gridfs/README.md create mode 100755 packages/gridfs/api.md create mode 100755 packages/gridfs/gridfs.client.js create mode 100755 packages/gridfs/gridfs.server.js create mode 100755 packages/gridfs/internal.api.md create mode 100755 packages/gridfs/package.js create mode 100755 packages/gridfs/tests/client-tests.js create mode 100755 packages/gridfs/tests/server-tests.js delete mode 100644 server/startup/plugins.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..9ccae96e --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["stage-2"] +} diff --git a/.meteor/packages b/.meteor/packages index 39f932d0..07364a14 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -18,7 +18,7 @@ juliancwirko:postcss # CSS post-processing plugin (replaces standard-mi standard-minifier-js@1.2.0 # a minifier plugin used for Meteor apps by default session@1.1.6 # ReactiveDict whose contents are preserved across Hot Code Push tracker@1.1.0 # Meteor transparent reactive programming library -mongo@1.1.11 +mongo@1.1.12 random@1.0.10 reactive-var@1.0.10 reactive-dict@1.1.8 @@ -34,7 +34,7 @@ email@1.1.17 service-configuration@1.0.10 amplify mdg:validated-method -shell-server +shell-server@0.2.1 # Meteor Auth Packages accounts-base@1.2.11 diff --git a/.meteor/release b/.meteor/release index 30b2c590..72980bc2 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.4.1 +METEOR@1.4.1.1 diff --git a/.meteor/versions b/.meteor/versions index f20f1d61..ce1570e3 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,10 +6,10 @@ accounts-password@1.3.0 accounts-twitter@1.1.11 alanning:roles@1.2.15 aldeed:autoform@5.8.1 -aldeed:collection2@2.9.1 -aldeed:collection2-core@1.1.1 -aldeed:schema-deny@1.0.1 -aldeed:schema-index@1.0.1 +aldeed:collection2@2.10.0 +aldeed:collection2-core@1.2.0 +aldeed:schema-deny@1.1.0 +aldeed:schema-index@1.1.0 aldeed:simple-schema@1.5.3 aldeed:template-extension@4.0.0 allow-deny@1.0.5 @@ -39,7 +39,7 @@ cfs:data-man@0.0.6 cfs:file@0.1.17 cfs:filesystem@0.1.2 cfs:graphicsmagick@0.0.18 -cfs:gridfs@0.0.33 +cfs:gridfs@0.0.34 cfs:http-methods@0.0.32 cfs:http-publish@0.0.13 cfs:power-queue@0.9.11 @@ -53,7 +53,7 @@ cfs:upload-http@0.0.20 cfs:worker@0.1.4 check@1.2.3 chuangbo:cookie@1.1.0 -coffeescript@1.2.4 +coffeescript@1.2.4_1 dburles:factory@1.1.0 ddp@1.2.5 ddp-client@1.3.1 @@ -112,12 +112,12 @@ mobile-status-bar@1.0.12 modules@0.7.6 modules-runtime@0.7.6 momentjs:moment@2.14.4 -mongo@1.1.11 +mongo@1.1.12 mongo-id@1.0.5 mongo-livedata@1.0.12 mrt:later@1.6.1 npm-bcrypt@0.9.1 -npm-mongo@1.5.46 +npm-mongo@1.5.48 oauth@1.1.11 oauth-encryption@1.2.0 oauth1@1.1.10 diff --git a/package.json b/package.json index c8d7efd1..beabb196 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "reaction", "description": "Reaction is a modern reactive, real-time event driven ecommerce platform.", - "version": "0.15.1", + "version": "0.15.2", "main": "main.js", "directories": { "test": "tests" @@ -69,6 +69,7 @@ }, "devDependencies": { "babel-eslint": "^6.1.2", + "babel-preset-stage-2": "^6.13.0", "eslint": "^3.3.1", "eslint-plugin-react": "^6.1.2" }, diff --git a/packages/gridfs/.npm/package/.gitignore b/packages/gridfs/.npm/package/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/packages/gridfs/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/gridfs/.npm/package/README b/packages/gridfs/.npm/package/README new file mode 100644 index 00000000..3d492553 --- /dev/null +++ b/packages/gridfs/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/packages/gridfs/.npm/package/npm-shrinkwrap.json b/packages/gridfs/.npm/package/npm-shrinkwrap.json new file mode 100644 index 00000000..3e69e09a --- /dev/null +++ b/packages/gridfs/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,89 @@ +{ + "dependencies": { + "bson": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-0.5.4.tgz", + "from": "bson@>=0.5.4 <0.6.0" + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "from": "buffer-shims@>=1.0.0 <2.0.0" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "from": "core-util-is@>=1.0.0 <1.1.0" + }, + "es6-promise": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "from": "es6-promise@3.2.1" + }, + "flushwritable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flushwritable/-/flushwritable-1.0.0.tgz", + "from": "flushwritable@>=1.0.0 <2.0.0" + }, + "gridfs-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/gridfs-stream/-/gridfs-stream-1.1.1.tgz", + "from": "gridfs-stream@1.1.1" + }, + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "from": "inherits@>=2.0.1 <2.1.0" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "from": "isarray@>=1.0.0 <1.1.0" + }, + "mongodb": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.9.tgz", + "from": "mongodb@2.2.9" + }, + "mongodb-core": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.0.11.tgz", + "from": "mongodb-core@2.0.11" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "from": "process-nextick-args@>=1.0.6 <1.1.0" + }, + "readable-stream": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", + "from": "readable-stream@2.1.5" + }, + "require_optional": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.0.tgz", + "from": "require_optional@>=1.0.0 <1.1.0" + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "from": "resolve-from@>=2.0.0 <3.0.0" + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "from": "semver@>=5.1.0 <6.0.0" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "from": "string_decoder@>=0.10.0 <0.11.0" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "from": "util-deprecate@>=1.0.1 <1.1.0" + } + } +} diff --git a/packages/gridfs/.travis.yml b/packages/gridfs/.travis.yml new file mode 100755 index 00000000..6a464003 --- /dev/null +++ b/packages/gridfs/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.10" +before_install: + - "curl -L http://git.io/s0Zu-w | /bin/sh" \ No newline at end of file diff --git a/packages/gridfs/.versions b/packages/gridfs/.versions new file mode 100755 index 00000000..9e122eb0 --- /dev/null +++ b/packages/gridfs/.versions @@ -0,0 +1,29 @@ +base64@1.0.3 +binary-heap@1.0.3 +callback-hook@1.0.3 +cfs:base-package@0.0.30 +cfs:gridfs@0.0.33 +cfs:storage-adapter@0.2.1 +check@1.0.5 +ddp@1.1.0 +deps@1.0.7 +ejson@1.0.6 +geojson-utils@1.0.3 +id-map@1.0.3 +jquery@1.11.3_2 +json@1.0.3 +livedata@1.0.13 +local-test:cfs:gridfs@0.0.33 +logging@1.0.7 +meteor@1.1.6 +minimongo@1.0.8 +mongo@1.1.0 +mongo-livedata@1.0.8 +ordered-dict@1.0.3 +raix:eventemitter@0.1.1 +random@1.0.3 +retry@1.0.3 +test-helpers@1.0.4 +tinytest@1.0.5 +tracker@1.0.7 +underscore@1.0.3 diff --git a/packages/gridfs/LICENSE.md b/packages/gridfs/LICENSE.md new file mode 100755 index 00000000..1a382082 --- /dev/null +++ b/packages/gridfs/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 [@raix](https://github.com/raix) and [@aldeed](https://github.com/aldeed), aka Morten N.O. Nørgaard Henriksen, mh@gi-software.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/gridfs/README.md b/packages/gridfs/README.md new file mode 100755 index 00000000..8b30fac8 --- /dev/null +++ b/packages/gridfs/README.md @@ -0,0 +1,48 @@ +cfs:gridfs +========================= + +NOTE: This package is under active development right now (2014-3-31). It has +bugs and the API may continue to change. Please help test it and fix bugs, +but don't use in production yet. + +A Meteor package that adds [GridFS](http://docs.mongodb.org/manual/core/gridfs/) file storage for +[CollectionFS](https://github.com/CollectionFS/Meteor-CollectionFS). When you +use this storage adapter, file data is stored in chunks in your MongoDB database. + +## Installation + +Install using Meteorite. When in a Meteor app directory, enter: + +``` +$ meteor add cfs:gridfs +``` + +## Usage + +```js +var imageStore = new FS.Store.GridFS("images", { + mongoUrl: 'mongodb://127.0.0.1:27017/test/', // optional, defaults to Meteor's local MongoDB + mongoOptions: {...}, // optional, see note below + transformWrite: myTransformWriteFunction, //optional + transformRead: myTransformReadFunction, //optional + maxTries: 1, // optional, default 5 + chunkSize: 1024*1024 // optional, default GridFS chunk size in bytes (can be overridden per file). + // Default: 2MB. Reasonable range: 512KB - 4MB +}); + +Images = new FS.Collection("images", { + stores: [imageStore] +}); +``` + +More control over the MongoDB connection is available by specifying [MongoClient.connect options](http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connect-options) as a `mongoOptions` attribute in the options object on the constructor. + +Refer to the [CollectionFS](https://github.com/CollectionFS/Meteor-CollectionFS) +package documentation for more information. + +## API + +[For Users](https://github.com/CollectionFS/Meteor-CollectionFS/blob/master/packages/gridfs/api.md) + +[For Contributors](https://github.com/CollectionFS/Meteor-CollectionFS/blob/master/packages/gridfs/internal.api.md) + diff --git a/packages/gridfs/api.md b/packages/gridfs/api.md new file mode 100755 index 00000000..aac97966 --- /dev/null +++ b/packages/gridfs/api.md @@ -0,0 +1,69 @@ +## cfs-gridfs Public API ## + +GridFS storage adapter for CollectionFS + +_API documentation automatically generated by [docmeteor](https://github.com/raix/docmeteor)._ + +- + +### new *fsStore*.GridFS(name, options)  Server ### + +*This method __GridFS__ is defined in `FS.Store`* + +__Arguments__ + +* __name__ *{String}* + + The store name + +* __options__ *{Object}* + * __beforeSave__ *{Function}* (Optional) + + Function to run before saving a file from the server. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + + * __maxTries__ *{Number}* (Optional, Default = 5) + + Max times to attempt saving a file + + +__Returns__ *{FS.StorageAdapter}* +An instance of FS.StorageAdapter. + + +Creates a GridFS store instance on the server. Inherits from FS.StorageAdapter +type. + +> ```FS.Store.GridFS = function(name, options) { ...``` [gridfs.server.js:16](gridfs.server.js#L16) + + +- + +### new *fsStore*.GridFS(name, options)  Client ### + +*This method __GridFS__ is defined in `FS.Store`* + +__Arguments__ + +* __name__ *{String}* + + The store name + +* __options__ *{Object}* + * __beforeSave__ *{Function}* (Optional) + + Function to run before saving a file from the client. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + + * __maxTries__ *{Number}* (Optional, Default = 5) + + Max times to attempt saving a file + + +__Returns__ *{undefined}* + + +Creates a GridFS store instance on the client, which is just a shell object +storing some info. + +> ```FS.Store.GridFS = function(name, options) { ...``` [gridfs.client.js:13](gridfs.client.js#L13) + + diff --git a/packages/gridfs/gridfs.client.js b/packages/gridfs/gridfs.client.js new file mode 100755 index 00000000..3cb26583 --- /dev/null +++ b/packages/gridfs/gridfs.client.js @@ -0,0 +1,21 @@ +/** + * @public + * @constructor + * @param {String} name - The store name + * @param {Object} options + * @param {Function} [options.beforeSave] - Function to run before saving a file from the client. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + * @param {Number} [options.maxTries=5] - Max times to attempt saving a file + * @returns {undefined} + * + * Creates a GridFS store instance on the client, which is just a shell object + * storing some info. + */ +FS.Store.GridFS = function(name, options) { + var self = this; + if (!(self instanceof FS.Store.GridFS)) + throw new Error('FS.Store.GridFS missing keyword "new"'); + + return new FS.StorageAdapter(name, options, { + typeName: 'storage.gridfs' + }); +}; diff --git a/packages/gridfs/gridfs.server.js b/packages/gridfs/gridfs.server.js new file mode 100755 index 00000000..37f2a8ab --- /dev/null +++ b/packages/gridfs/gridfs.server.js @@ -0,0 +1,171 @@ +var path = Npm.require('path'); +var mongodb = Npm.require('mongodb'); +var ObjectID = Npm.require('mongodb').ObjectID; +var Grid = Npm.require('gridfs-stream'); +//var Grid = Npm.require('gridfs-locking-stream'); + +var chunkSize = 1024*1024*2; // 256k is default GridFS chunk size, but performs terribly for largish files + +/** + * @public + * @constructor + * @param {String} name - The store name + * @param {Object} options + * @param {Function} [options.beforeSave] - Function to run before saving a file from the server. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + * @param {Number} [options.maxTries=5] - Max times to attempt saving a file + * @returns {FS.StorageAdapter} An instance of FS.StorageAdapter. + * + * Creates a GridFS store instance on the server. Inherits from FS.StorageAdapter + * type. + */ + +FS.Store.GridFS = function(name, options) { + var self = this; + options = options || {}; + + var gridfsName = name; + var mongoOptions = options.mongoOptions || {}; + + if (!(self instanceof FS.Store.GridFS)) + throw new Error('FS.Store.GridFS missing keyword "new"'); + + if (!options.mongoUrl) { + options.mongoUrl = process.env.MONGO_URL; + // When using a Meteor MongoDB instance, preface name with "cfs_gridfs." + gridfsName = "cfs_gridfs." + name; + } + + if (!options.mongoOptions) { + options.mongoOptions = { db: { native_parser: true }, server: { auto_reconnect: true }}; + } + + if (options.chunkSize) { + chunkSize = options.chunkSize; + } + + return new FS.StorageAdapter(name, options, { + + typeName: 'storage.gridfs', + fileKey: function(fileObj) { + // We should not have to mount the file here - We assume its taken + // care of - Otherwise we create new files instead of overwriting + var key = { + _id: null, + filename: null + }; + + // If we're passed a fileObj, we retrieve the _id and filename from it. + if (fileObj) { + var info = fileObj._getInfo(name, {updateFileRecordFirst: false}); + key._id = info.key || null; + key.filename = info.name || fileObj.name({updateFileRecordFirst: false}) || (fileObj.collectionName + '-' + fileObj._id); + } + + // If key._id is null at this point, createWriteStream will let GridFS generate a new ID + return key; + }, + createReadStream: function(fileKey, options) { + options = options || {}; + + // Init GridFS + var gfs = new Grid(self.db, mongodb); + + // Set the default streamning settings + var settings = { + _id: new ObjectID(fileKey._id), + root: gridfsName + }; + + // Check if this should be a partial read + if (typeof options.start !== 'undefined' && typeof options.end !== 'undefined' ) { + // Add partial info + settings.range = { + startPos: options.start, + endPos: options.end + }; + } + + FS.debug && console.log('GRIDFS', settings); + + return gfs.createReadStream(settings); + + }, + createWriteStream: function(fileKey, options) { + options = options || {}; + + // Init GridFS + var gfs = new Grid(self.db, mongodb); + + var opts = { + filename: fileKey.filename, + mode: 'w', + root: gridfsName, + chunk_size: options.chunk_size || chunkSize, + // We allow aliases, metadata and contentType to be passed in via + // options + aliases: options.aliases || [], + metadata: options.metadata || null, + content_type: options.contentType || 'application/octet-stream' + }; + + if (fileKey._id) { + opts._id = new ObjectID(fileKey._id); + } + + var writeStream = gfs.createWriteStream(opts); + + writeStream.on('close', function(file) { + if (!file) { + // gridfs-stream will emit "close" without passing a file + // if there is an error. We can simply exit here because + // the "error" listener will also be called in this case. + return; + } + + if (FS.debug) console.log('SA GridFS - DONE!'); + + // Emit end and return the fileKey, size, and updated date + writeStream.emit('stored', { + // Set the generated _id so that we know it for future reads and writes. + // We store the _id as a string and only convert to ObjectID right before + // reading, writing, or deleting. If we store the ObjectID itself, + // Meteor (EJSON?) seems to convert it to a LocalCollection.ObjectID, + // which GFS doesn't understand. + fileKey: file._id.toString(), + size: file.length, + storedAt: file.uploadDate || new Date() + }); + }); + + writeStream.on('error', function(error) { + console.log('SA GridFS - ERROR!', error); + }); + + return writeStream; + + }, + remove: function(fileKey, callback) { + // Init GridFS + var gfs = new Grid(self.db, mongodb); + + try { + gfs.remove({ _id: new ObjectID(fileKey._id), root: gridfsName }, callback); + } catch(err) { + callback(err); + } + }, + + // Not implemented + watch: function() { + throw new Error("GridFS storage adapter does not support the sync option"); + }, + + init: function(callback) { + mongodb.MongoClient.connect(options.mongoUrl, mongoOptions, function (err, db) { + if (err) { return callback(err); } + self.db = db; + callback(null); + }); + } + }); +}; diff --git a/packages/gridfs/internal.api.md b/packages/gridfs/internal.api.md new file mode 100755 index 00000000..cb81e743 --- /dev/null +++ b/packages/gridfs/internal.api.md @@ -0,0 +1,75 @@ +## Public and Private API ## + +_API documentation automatically generated by [docmeteor](https://github.com/raix/docmeteor)._ + +*** + +__File: ["gridfs.server.js"](gridfs.server.js) Where: {server}__ + +*** + +### new *fsStore*.GridFS(name, options)  Server ### + +*This method __GridFS__ is defined in `FS.Store`* + +__Arguments__ + +* __name__ *{String}* + + The store name + +* __options__ *{Object}* + * __beforeSave__ *{Function}* (Optional) + + Function to run before saving a file from the server. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + + * __maxTries__ *{Number}* (Optional, Default = 5) + + Max times to attempt saving a file + + +__Returns__ *{FS.StorageAdapter}* +An instance of FS.StorageAdapter. + + +Creates a GridFS store instance on the server. Inherits from FS.StorageAdapter +type. + +> ```FS.Store.GridFS = function(name, options) { ...``` [gridfs.server.js:16](gridfs.server.js#L16) + + +*** + +__File: ["gridfs.client.js"](gridfs.client.js) Where: {client}__ + +*** + +### new *fsStore*.GridFS(name, options)  Client ### + +*This method __GridFS__ is defined in `FS.Store`* + +__Arguments__ + +* __name__ *{String}* + + The store name + +* __options__ *{Object}* + * __beforeSave__ *{Function}* (Optional) + + Function to run before saving a file from the client. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties. + + * __maxTries__ *{Number}* (Optional, Default = 5) + + Max times to attempt saving a file + + +__Returns__ *{undefined}* + + +Creates a GridFS store instance on the client, which is just a shell object +storing some info. + +> ```FS.Store.GridFS = function(name, options) { ...``` [gridfs.client.js:13](gridfs.client.js#L13) + + diff --git a/packages/gridfs/package.js b/packages/gridfs/package.js new file mode 100755 index 00000000..84fe8ebb --- /dev/null +++ b/packages/gridfs/package.js @@ -0,0 +1,25 @@ +Package.describe({ + name: "cfs:gridfs", + version: "0.0.34", + summary: "GridFS storage adapter for CollectionFS", + git: "https://github.com/CollectionFS/Meteor-cfs-gridfs.git" +}); + +Npm.depends({ + "mongodb": "2.2.9", + "gridfs-stream": "1.1.1" +}); + +Package.onUse(function (api) { + api.versionsFrom("1.0"); + + api.use(["cfs:base-package@0.0.30", "cfs:storage-adapter@0.2.1"]); + api.addFiles("gridfs.server.js", "server"); + api.addFiles("gridfs.client.js", "client"); +}); + +Package.onTest(function (api) { + api.use(["cfs:gridfs", "test-helpers", "tinytest"], "server"); + api.addFiles("tests/server-tests.js", "server"); + api.addFiles("tests/client-tests.js", "client"); +}); diff --git a/packages/gridfs/tests/client-tests.js b/packages/gridfs/tests/client-tests.js new file mode 100755 index 00000000..222af562 --- /dev/null +++ b/packages/gridfs/tests/client-tests.js @@ -0,0 +1,44 @@ +function equals(a, b) { + return !!(EJSON.stringify(a) === EJSON.stringify(b)); +} + +Tinytest.add('cfs-gridfs - client - test environment', function(test) { + test.isTrue(typeof FS.Collection !== 'undefined', 'test environment not initialized FS.Collection'); + test.isTrue(typeof CFSErrorType !== 'undefined', 'test environment not initialized CFSErrorType'); +}); + +/* + * FS.File Client Tests + * + * construct FS.File with no arguments + * construct FS.File passing in File + * construct FS.File passing in Blob + * load blob into FS.File and then call FS.File.toDataUrl + * call FS.File.setDataFromBinary, then FS.File.getBlob(); make sure correct data is returned + * load blob into FS.File and then call FS.File.getBinary() with and without start/end; make sure correct data is returned + * construct FS.File, set FS.File.collectionName to a CFS name, and then test FS.File.update/remove/get/put/del/url + * set FS.File.name to a filename and test that FS.File.getExtension() returns the extension + * load blob into FS.File and make sure FS.File.saveLocal initiates a download (possibly can't do automatically) + * + */ + + +//Test API: +//test.isFalse(v, msg) +//test.isTrue(v, msg) +//test.equalactual, expected, message, not +//test.length(obj, len) +//test.include(s, v) +//test.isNaN(v, msg) +//test.isUndefined(v, msg) +//test.isNotNull +//test.isNull +//test.throws(func) +//test.instanceOf(obj, klass) +//test.notEqual(actual, expected, message) +//test.runId() +//test.exception(exception) +//test.expect_fail() +//test.ok(doc) +//test.fail(doc) +//test.equal(a, b, msg) diff --git a/packages/gridfs/tests/server-tests.js b/packages/gridfs/tests/server-tests.js new file mode 100755 index 00000000..61a7a3f9 --- /dev/null +++ b/packages/gridfs/tests/server-tests.js @@ -0,0 +1,49 @@ +function equals(a, b) { + return !!(EJSON.stringify(a) === EJSON.stringify(b)); +} + +Tinytest.add('cfs-gridfs - server - test environment', function(test) { + test.isTrue(typeof FS.Collection !== 'undefined', 'test environment not initialized FS.Collection'); + test.isTrue(typeof CFSErrorType !== 'undefined', 'test environment not initialized CFSErrorType'); +}); + +/* + * FS.File Server Tests + * + * construct FS.File with no arguments + * load data with FS.File.setDataFromBuffer + * load data with FS.File.setDataFromBinary + * load data and then call FS.File.toDataUrl with and without callback + * load buffer into FS.File and then call FS.File.getBinary with and without start/end; make sure correct data is returned + * construct FS.File, set FS.File.collectionName to a CFS name, and then test FS.File.update/remove/get/put/del/url + * (call these with and without callback to test sync vs. async) + * set FS.File.name to a filename and test that FS.File.getExtension() returns the extension + * + * + * FS.Collection Server Tests + * + * Make sure options.filter is respected + * + * + */ + + +//Test API: +//test.isFalse(v, msg) +//test.isTrue(v, msg) +//test.equalactual, expected, message, not +//test.length(obj, len) +//test.include(s, v) +//test.isNaN(v, msg) +//test.isUndefined(v, msg) +//test.isNotNull +//test.isNull +//test.throws(func) +//test.instanceOf(obj, klass) +//test.notEqual(actual, expected, message) +//test.runId() +//test.exception(exception) +//test.expect_fail() +//test.ok(doc) +//test.fail(doc) +//test.equal(a, b, msg) diff --git a/server/startup/accounts.js b/server/startup/accounts.js index dddc4176..2567e759 100644 --- a/server/startup/accounts.js +++ b/server/startup/accounts.js @@ -82,7 +82,7 @@ export default function () { const defaultRoles = ["guest", "account/profile", "product", "tag", "index", "cart/checkout", "cart/completed"]; const roles = {}; const additionals = { - profile: {} + profile: Object.assign({}, options && options.profile) }; if (!user.emails) user.emails = []; // init default user roles diff --git a/server/startup/index.js b/server/startup/index.js index 72b16d41..8e29e0a3 100644 --- a/server/startup/index.js +++ b/server/startup/index.js @@ -2,7 +2,6 @@ import Accounts from "./accounts"; import i18n from "./i18n"; import Load from "./load-data"; import Packages from "./packages"; -import Plugins from "./plugins"; import Registry from "./registry"; import Init from "./init"; @@ -11,7 +10,6 @@ export default function () { i18n(); Load(); Packages(); - Plugins(); Registry(); Init(); } diff --git a/server/startup/plugins.js b/server/startup/plugins.js deleted file mode 100644 index af29262b..00000000 --- a/server/startup/plugins.js +++ /dev/null @@ -1,160 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { Logger } from "/server/api"; - - -/** - * Synchronously check if a file or directory is empty or doesn't exist - * @param {String} searchPath - path to file or directory - * @return {Boolean} - returns true if file or directory isn't empty - */ -function isEmptyOrMissing(searchPath) { - let stat; - try { - stat = fs.statSync(searchPath); - } catch (e) { - return true; - } - if (stat.isDirectory()) { - const items = fs.readdirSync(searchPath); - return !items || !items.length; - } - const file = fs.readFileSync(searchPath); - return !file || !file.length; -} - -// add a message to the top of the plugins import file -const importFileMessage = ` -/** - * ***** DO NOT EDIT THIS FILE MANUALLY ***** - * This file is generated automatically by the Reaction - * plugin loader and will be reset at each startup. - */ - -`; - -/** - * Dynamically create a plugin imports file on client or server - * @param {String} file - absolute path to file to write - * @param {Array} imports - array of import path strings - * @return {Boolean} returns true if no error - */ -function generateImportsFile(file, imports) { - // create/reset imports file - try { - Logger.info(`Resetting plugins file at ${file}`); - fs.writeFileSync(file, ""); - fs.writeFileSync(file, importFileMessage); - } catch (e) { - Logger.error(e, `Failed to reset plugins file at ${file}`); - throw new Meteor.Error(e); - } - - // populate plugins file with imports - imports.forEach((importPath) => { - try { - fs.appendFileSync(file, `import "${importPath}";\n`); - } catch (e) { - Logger.error(e, `Failed to write to plugins file at ${importPath}`); - throw new Meteor.Error(e); - } - }); -} - - -/** - * Import Reaction plugins - * @param {String} baseDirPath - path to a plugins sub-directory (core/included/custom) - * @return {Object} - returns object with client and server keys that contain arrays - */ -function getImportPaths(baseDirPath) { - // get an array of directories at a path - const getDirectories = (dir) => { - return fs.readdirSync(dir).filter((file) => { - return fs.statSync(path.join(dir, file)).isDirectory(); - }); - }; - - // get app root path - const appRoot = path.resolve(".").split(".meteor")[0]; - - // create the import path - const getImportPath = (pluginFile) => { - const importPath = "/" + path.relative(appRoot, pluginFile); - return importPath.replace(/\\/g, "/"); - }; - - // get all plugin directories at provided base path - const pluginDirs = getDirectories(baseDirPath); - - const clientImportPaths = []; - const serverImportPaths = []; - const registryImportPaths = []; - - // read registry.json and require server/index.js if they exist - pluginDirs.forEach((plugin) => { - const clientImport = baseDirPath + plugin + "/client/index.js"; - const serverImport = baseDirPath + plugin + "/server/index.js"; - const registryImport = baseDirPath + plugin + "/register.js"; - - // import the client files if they exist - if (!isEmptyOrMissing(clientImport)) { - Logger.info(`Client import found for ${plugin}`); - clientImportPaths.push(getImportPath(clientImport.replace("/index.js", ""))); - } - - // import the server files if they exist - if (!isEmptyOrMissing(serverImport)) { - Logger.info(`Server import found for ${plugin}`); - serverImportPaths.push(getImportPath(serverImport.replace("/index.js", ""))); - } - - // import plugin registry files - if (!isEmptyOrMissing(registryImport)) { - Logger.info(`Registry file found for ${plugin}`); - registryImportPaths.push(getImportPath(registryImport)); - } - }); - - return { - client: clientImportPaths, - server: serverImportPaths, - registry: registryImportPaths - }; -} - - -/** - * Define base plugin paths - */ -const pluginsPath = path.resolve(".").split(".meteor")[0] + "imports/plugins/"; -const corePlugins = pluginsPath + "core/"; -const includedPlugins = pluginsPath + "included/"; -const customPlugins = pluginsPath + "custom/"; - - -export default function () { - if (process.env.NODE_ENV !== "production" && !Meteor.isAppTest) { - // get imports from each plugin directory - const core = getImportPaths(corePlugins); - const included = getImportPaths(includedPlugins); - const custom = getImportPaths(customPlugins); - - // concat all imports - const clientImports = [].concat(core.client, included.client, custom.client); - const serverImports = [].concat( - core.server, - included.server, - custom.server, - core.registry, - included.registry, - custom.registry - ); - - const appRoot = path.resolve(".").split(".meteor")[0]; - - // create import files on client and server and write import statements - generateImportsFile(appRoot + "client/plugins.js", clientImports); - generateImportsFile(appRoot + "server/plugins.js", serverImports); - } -}