Skip to content

Commit

Permalink
#32: Added documentation, updated jsdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
Pagebakers committed Dec 30, 2014
1 parent 5d67eb5 commit 873e6e1
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 100 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ Slingshot.createDirective("myFileUploads", Slingshot.S3Storage, {
This directive will not allow any files other than images to be uploaded. The
policy is directed by the meteor app server and enforced by AWS S3.

## Client side validation

On both client and server side we declare file restrictions for our directive:

```Javascript
Slingshot.fileRestrictions("myFileUploads", {
allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
maxSize: 1*0x400*0x400, //1MB,
authorize: function() {
return this.userId
}
});
```

Now Slingshot will validate the file before sending the authorization request to the server.


### Manual validation
```JavaScript
var uploader = new Slingshot.Upload("myFileUploads");

var isValid = uploader.validate(document.getElementById('input').files[0]);
if (isValid !== true) {
console.error(isValid);
}
```

The validate method will return `true` if valid and returns an `Error instance` if validation fails.


## Storage services

The client side is agnostic to which storage service is used. All it
Expand Down Expand Up @@ -253,3 +283,13 @@ authorization will expire after the request was made. Default is 5 minutes.

`GoogleSecretKey` String (required for Google Cloud Storage) - Can also be set
in `Meteor.settings`

### File restrictions

`authorize`: Function (optional) - Function to determines if upload is allowed.

`maxSize`: Number (optional) - Maximum file-size (in bytes). Use `null` or `0`
for unlimited.

`allowedFileTypes` RegExp, String or Array (optional) - Allowed MIME types. Use
null for any file type.
1 change: 0 additions & 1 deletion lib/directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ _.extend(Slingshot.Directive.prototype, {
* @param {Object} context
* @param {FileInfo} file
* @param {Object} [meta]
* @param {Function} [authorize]
*
* @returns {Boolean}
*/
Expand Down
99 changes: 1 addition & 98 deletions lib/restrictions.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,101 +50,4 @@ Slingshot.fileRestrictions = function (name, restrictions) {

Slingshot.getRestrictions = function (name) {
return this._restrictions[name] || {};
};

Slingshot.Validators = {

/**
*
* @method authorize
*
* @throws Meteor.Error
*
* @param {Object} context
* @param {FileInfo} file
* @param {Object} [meta]
* @param {Object} [restrictions]
*
* @returns {Boolean}
*/

authorize: function (context, file, meta, restrictions) {
return this.checkFileSize(file.size, restrictions.maxSize) &&
this.checkFileType(file.type, restrictions.allowedFileTypes) &&
(typeof restrictions.authorize !== 'function' ||
restrictions.authorize.call(context, file, meta));
},

/**
* @throws Meteor.Error
*
* @param {Number} size - Size of file in bytes.
* @param {Number} maxSize - Max size of file in bytes.
* @returns {boolean}
*/

checkFileSize: function (size, maxSize) {
maxSize = Math.min(maxSize, Infinity);

if (maxSize && size > maxSize)
throw new Meteor.Error("Upload denied", "File exceeds allowed size of " +
formatBytes(maxSize));

return true;
},

/**
*
* @throws Meteor.Error
*
* @param {String} type - Mime type
* @param {RegExp,Array,String} allowed - Allowed file type(s)
* @returns {boolean}
*/

checkFileType: function (type, allowed) {
if (allowed instanceof RegExp) {

if (!allowed.test(type))
throw new Meteor.Error("Upload denied",
type + " is not an allowed file type");

return true;
}

if (_.isArray(allowed)) {
if (allowed.indexOf(type) < 0) {
throw new Meteor.Error("Upload denied",
type + " is not one of the followed allowed file types: " +
allowed.join(", "));
}

return true;
}

if (allowed !== type) {
throw new Meteor.Error("Upload denied", "Only file of type " + allowed +
" can be uploaded");
}

return true;
}
};

/** Human readable data-size in bytes.
*
* @param size {Number}
* @returns {string}
*/

function formatBytes(size) {
var units = ['Bytes', 'KB', 'MB', 'GB', 'TB'],
unit = units.shift();

while (size >= 0x400 && units.length) {
size /= 0x400;
unit = units.shift();
}

return (Math.round(size * 100) / 100) + " " + unit;
}
};
5 changes: 5 additions & 0 deletions lib/upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ Slingshot.Upload = function (directive, metaData) {
return loaded.get();
},

/**
* @param {File} file
* @returns {Boolean|Error} Returns to on success, Error on failure.
*/

validate: function(file) {
var context = {
userId: Meteor.userId()
Expand Down
96 changes: 96 additions & 0 deletions lib/validators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
Slingshot.Validators = {

/**
*
* @method authorize
*
* @throws Meteor.Error
*
* @param {Object} context
* @param {FileInfo} file
* @param {Object} [meta]
* @param {Object} [restrictions]
*
* @returns {Boolean}
*/

authorize: function (context, file, meta, restrictions) {
return this.checkFileSize(file.size, restrictions.maxSize) &&
this.checkFileType(file.type, restrictions.allowedFileTypes) &&
(typeof restrictions.authorize !== 'function' ||
restrictions.authorize.call(context, file, meta));
},

/**
* @throws Meteor.Error
*
* @param {Number} size - Size of file in bytes.
* @param {Number} maxSize - Max size of file in bytes.
* @returns {boolean}
*/

checkFileSize: function (size, maxSize) {
maxSize = Math.min(maxSize, Infinity);

if (maxSize && size > maxSize)
throw new Meteor.Error("Upload denied", "File exceeds allowed size of " +
formatBytes(maxSize));

return true;
},

/**
*
* @throws Meteor.Error
*
* @param {String} type - Mime type
* @param {RegExp|Array|String} allowed - Allowed file type(s)
* @returns {boolean}
*/

checkFileType: function (type, allowed) {
if (allowed instanceof RegExp) {

if (!allowed.test(type))
throw new Meteor.Error("Upload denied",
type + " is not an allowed file type");

return true;
}

if (_.isArray(allowed)) {
if (allowed.indexOf(type) < 0) {
throw new Meteor.Error("Upload denied",
type + " is not one of the followed allowed file types: " +
allowed.join(", "));
}

return true;
}

if (allowed !== type) {
throw new Meteor.Error("Upload denied", "Only file of type " + allowed +
" can be uploaded");
}

return true;
}
};

/** Human readable data-size in bytes.
*
* @param size {Number}
* @returns {string}
*/

function formatBytes(size) {
var units = ['Bytes', 'KB', 'MB', 'GB', 'TB'],
unit = units.shift();

while (size >= 0x400 && units.length) {
size /= 0x400;
unit = units.shift();
}

return (Math.round(size * 100) / 100) + " " + unit;
}
5 changes: 4 additions & 1 deletion package.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ Package.on_use(function (api) {
api.use(["underscore", "check"]);
api.use(["tracker", "reactive-var"], "client");

api.add_files("lib/restrictions.js", ["client", "server"]);
api.add_files([
"lib/restrictions.js",
"lib/validators.js"
], ["client", "server"]);
api.add_files("lib/upload.js", "client");
api.add_files([
"lib/directive.js",
Expand Down

0 comments on commit 873e6e1

Please sign in to comment.