UNPKG

built.io-browserify

Version:

SDK for Built.io Backend which is compatible with Browserify

747 lines (712 loc) 23.7 kB
var R = require('ramda'); var when = require('when'); var utility = require('./utilities/utility'); var instanceMethodBuilder = require('./utilities/instanceMethodBuilder')(); var fileUploader = require('./utilities/uploadHelper'); var constants = require('./constants'); var Built = require('./built'); var Events = require('./events'); var node = require('./node'); var https = node.https; var path = node.path; var fs; if(!utility.isBrowser()){ // only when in node envirnoment fs = node.fs; } var callbackTray = {}; //object to keep track of which upload go completed if(utility.isBrowser()){ // activates the listeners on file load attachPostMsgListener(); } /** * @class Upload * @classdesc With "uploads", you can store files on Built.io Backend.Uploads on Built.io Backend are similar to objects. Each upload object holds a file, and they have an unique uid. * @param {String|Buffer|Input|File|FormData|base64|Bytes} File Accepts a File to be uploaded or Uid of an existing file * @description * Represents an upload on Built.io Backend * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * * <h3><u>On Browser</u></h3> * // Example using input element * var upload = Built.App('blt5d4sample2633b').Upload() * upload = upload.setFile(document.getElementById('input_element')); * upload * .save() * .then(function(upload){ * console.log(upload.toJSON()) * }) * * //fileObj could be a instance of File or FormData * var upload = Built.App('blt5d4sample2633b').Upload(fileObj); * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * * <h3><u>On Node</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload("/home/abc/Pictures/game-over.jpg"); // File path * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * var buffer = fs.readFileSync('images/cartoon.jpeg'); * var upload = Built.App('blt5d4sample2633b').Upload({ * bytes : buffer, * contentType: 'image/jpeg', * name: 'jerry.jpeg' * }); * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * <h3><u>Common</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload({ * base64: "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE", * contentType: 'image/jpeg', //Optional * name: 'cartoon.jpg' * }); * @return {Upload} */ var uploadCons = module.exports = R.curry(function(app, headers, params, file) { var data = {}; if(utility.isString(file) && file.match(/^blt[a-z0-9]*/i)) // uid of file data['uid'] = file; else if(!R.isEmpty(R.keys(file)) && file.name && (file.base64 || file.bytes)){ //Constructor is used to initial file data = fileUploader.checkNInsertFile(data, file); } else{ data = file } var returnObj = { app : app, headers : headers, params : params, data : data, toJSON : function() { return params; } } installPlugins(returnObj); return instanceMethodBuilder.build(module.exports,returnObj); }); /* pluginsHelper is global variable declared in built.js */ function installPlugins(returnObj){ pluginsHelper.plugins.map(function(plugin){ if(plugin.realtime && plugin.realtime.onUploadInstance){ plugin.realtime.onUploadInstance(returnObj); } }); }; /** * Downloads the file * @function download * @instance * @memberof Upload * @throws throw new Error("Object cannot be downloaded as download link not found"); * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * * <h3><u>On Browser</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload(formData); // formData is instance of FormData * upload.fetch() * .then(function(upload){ * upload.download(); // A new tab is opened and the file gets downloaded. * }); * * <h3><u>On Node</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload(formData); // formData is instance of FormData * upload.fetch() * .then(function(upload){ * upload.download() * .then(function(stream){ * // a nodejs 'Stream' is returned * }); * }); * @return {Promise<Stream>} */ module.exports.download = function(upload){ if(!upload.getDownloadLink()) throw new Error("Object cannot be downloaded as download link not found"); if(utility.isBrowser()){ window.open(upload.getDownloadLink()); }else{ var deferred = when.defer(); https.get(upload.getDownloadLink(), function(response) { deferred.resolve(response); }); return deferred.promise; } } instanceMethodBuilder.define('download',1); /** * Helps in determining whether a uid is assigned to this upload or not * @function isNew * @param {String} uid Uid of the upload * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var person = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b') * var boolean = person.isNew(); // true * @return {Object} */ module.exports.isNew = function(upload){ return !! upload.data.uid; } instanceMethodBuilder.define('isNew',1); /** * Sets the uid for this upload object * @function setUid * @param {String} uid Uid of the existing built upload object * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * var upload = Built.App('blt5d4sample2633b').Upload(); * upload = upload.setUid('blt212sample24a6b'); * @return {String} */ module.exports.setUid = R.curry(function(uid,upload){ var newData = R.mixin({},getData(upload)); newData['uid'] = uid; return uploadCons(upload.app,upload.headers,upload.params,newData); }); instanceMethodBuilder.define('setUid',2); /** * Gets the uid associated with this upload object * @function getUid * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * var upload = Built.App('blt5d4sample2633b').Upload(formData); // formData is instance of FormData * upload.fetch() * .then(function(upload){ * upload.getUid(); * }); * @return {String} */ var getUid = module.exports.getUid = function(upload){ return getData(upload).uid; } instanceMethodBuilder.define('getUid',1); var getUploadPayload = module.exports.getUploadPayload = function(upload){ if(getData(upload).file){ return getData(upload).file } else if(getData(upload).encodedUpload){ return getData(upload).encodedUpload } else{ return getData(upload).uid } } instanceMethodBuilder.define('getUploadPayload',1); /** * Assigns file to an object * @function setFile * @param {File} file Accepts a form input element, File instance or FormData instance * @throws new Error("Invalid file path: /home/user/..."); * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * * <h3><u>On Browser</u></h3> * // Example using input element * var upload = Built.App('blt5d4sample2633b').Upload() * .setFile(document.getElementById('input_element')); * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }) * * //fileObj could be a instance of File or FormData * var upload = Built.App('blt5d4sample2633b').Upload(fileObj); * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * * <h3><u>On Node</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload("/home/abc/Pictures/game-over.jpg"); // File path * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * var buffer = fs.readFileSync('images/cartoon.jpeg'); * var upload = Built.App('blt5d4sample2633b').Upload({ * bytes : buffer, * contentType: 'image/jpeg', * name: 'jerry.jpeg' * }); * upload.save() * .then(function(upload){ * console.log(upload.toJSON()) * }); * <h3><u>Common</u></h3> * var upload = Built.App('blt5d4sample2633b').Upload({ * base64: "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE", * contentType: 'image/jpeg', //Optional * name: 'cartoon.jpg' * }); * @return {Upload} */ module.exports.setFile = R.curry(function(file,upload){ var newData = R.mixin({},getData(upload)); return uploadCons(upload.app,upload.headers,upload.params,fileUploader.checkNInsertFile(newData, file)); }); instanceMethodBuilder.define('setFile',2); /** * Removes a file * @function unsetFile * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * var upload = Built.App('blt5d4sample2633b').Upload(); * upload = upload.setFile('/home/abc/Pictures/game-over.jpg'); * upload = upload.unsetFile(); * @return {Upload} */ module.exports.unsetFile = function(upload){ if(getUid(upload)){ return uploadCons(upload.app,upload.headers,upload.params,data.uid); } return uploadCons(upload.app,upload.headers,upload.params,{}); } instanceMethodBuilder.define('unsetFile',1); /** * Saves/Updates the upload * @function save * @instance * @memberof Upload * @fires upload:start and upload:end events of {@link Events} * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // Creates a new upload as upload object does not have a uid property set * var upload = Built.App('blt5d4sample2633b').Upload(); * upload = upload.setFile('/home/abc/Pictures/game-over.jpg'); * upload.save() * .then(function(upload){ * // do something here * }); * * //Updates the existing upload as upload object has a uid property set * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); //upload_uid * upload = upload.setFile('/home/abc/Pictures/game-over.jpg'); * upload.save() * .then(function(upload){ * // do something here * }); * @return {Promise<Upload>} */ module.exports.save = function(upload){ var dataPayLoad = getUploadPayload(upload); if (dataPayLoad) { if (utility.isBrowser()) { if(getData(upload).encodedUpload){ return uploadEncodedFile(getData(upload).encodedUpload, upload); } if (utility.supportsFormData()) { return fileUploader.uploadViaFormData(upload.app.options.adaptor, getUploadPayload(upload), module.exports.getCombinedHeaders(upload), module.exports.getURL(upload), { upload:getParams(upload) }, getRequestMethod(upload), constants.UPLOAD_KEY_NAME) .then(function(res){ var parsedResponse = JSON.parse(res); return uploadCons(upload.app,upload.headers,parsedResponse.upload,parsedResponse.upload.uid); }); } else { if (getUploadPayload(upload).getAttribute('type') == 'file') { return uploadViaIFramePosting(upload); } else { throw new Error('Input file element required for upload'); } } } else { return uploadViaNode(upload); } } else { throw new Error('No upload found'); } } instanceMethodBuilder.define('save',1); /** * Deletes the upload from Built.io Backend * @function delete * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload * .delete() * .then(function(){ * // do something here * }); * @return {Promise<null>} */ module.exports.delete = function(upload){ var adaptor = upload.app.options.adaptor; if (!getUid(upload)) { throw new Error('Upload object needs to be associated with a uid'); } var requestObject = utility.getAdaptorObj('DELETE', module.exports.getURL(upload), module.exports.getCombinedHeaders(upload), null, null); return adaptor.makeCall(requestObject).then(function(response) { return null; }); } instanceMethodBuilder.define('delete',1); /** * Fetches the upload from Built.io Backend * @function fetch * @throws new Error('Upload object needs to be associated with a uid'); * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload * .fetch() * .then(function(upload){ * // do something here * }); * @return {Promise<Upload>} */ module.exports.fetch = function(upload) { var adaptor = upload.app.options.adaptor; if (!getUid(upload)) { throw new Error('Upload object needs to be associated with a uid'); } var requestObject = utility.getAdaptorObj('GET', module.exports.getURL(upload), module.exports.getCombinedHeaders(upload),null,null); return adaptor.makeCall(requestObject).then(function(response) { return uploadCons(upload.app,module.exports.getCombinedHeaders(upload),response.entity.upload,response.entity.upload.uid); }); } instanceMethodBuilder.define('fetch',1); var set = R.curry(function(name,value,upload){ var newParams = R.mixin({},getParams(upload)); newParams[name] = value; return uploadCons(upload.app,upload.headers,newParams,upload.data); }); /** * Sets ACL on an upload * @function setACL * @param {ACL} aclObject The ACL object * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * var upload = Built.App('blt5d4sample2633b').Upload(); * var acl = Built.ACL(); * acl = acl.setPublicReadAccess(true); * upload = upload.setACL(acl); * @return {Upload} */ module.exports.setACL = R.curry(function(aclObject,upload){ var newParams = R.mixin({},getParams(upload)); newParams['ACL'] = aclObject.toJSON(); return uploadCons(upload.app,upload.headers,newParams,upload.data); }) instanceMethodBuilder.define('setACL',2); /** * Gets the ACL object from an upload * @function getACL * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload.fetch() * .then(function(upload){ * var acl = upload.getACL(); * console.log(acl.toJSON()) * }) * @return {ACL} */ module.exports.getACL = function(upload){ return Built.ACL(getParams(upload).ACL); } instanceMethodBuilder.define('getACL',1); /** * Assigns tag(s) to an upload * @function setTags * @param {Array} tag Array of tags that you want to associate this upload with * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload = upload.setTags(['tag1','tag2']); * @return {Upload} */ module.exports.setTags = set('tags'); instanceMethodBuilder.define('setTags',2); var getParamsHelper = R.curry(function(parameter,upload){ return getParams(upload)[parameter]; }); /** * Gets the download link for the upload * @function getDownloadLink * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * var upload = Built.App('blt5d4sample2633b').Upload(formData); // formData is instance of FormData * upload.save() * .then(function(upload){ * var link = upload.getDownloadLink(); * }); * @return {String} */ module.exports.getDownloadLink = getParamsHelper('url'); instanceMethodBuilder.define('getDownloadLink',1); /** * Gets the tag(s) assigned to an upload * @function getTags * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload * .fetch() * .then(function(upload){ * upload.getTags(); // Returns the ACL for this upload * }); * @return {Array} */ module.exports.getTags = getParamsHelper('tags'); instanceMethodBuilder.define('getTags',1); /** * Gets the content type of an upload * @function getContentType * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload * .fetch() * .then(function(upload){ * upload.getContentType(); * }) * @return {String} */ module.exports.getContentType = getParamsHelper('content_type'); instanceMethodBuilder.define('getContentType',1); /** * Gets the file size of the upload * @function getFileSize * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload.fetch() * .then(function(upload){ * upload.getFileSize(); * }) * @return {String} */ module.exports.getFileSize = getParamsHelper('file_size'); instanceMethodBuilder.define('getFileSize',1); /** * Gets the file name of the upload * @function getFileName * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload.fetch() * .then(function(upload){ * upload.getFileName(); * }) * @return {String} */ module.exports.getFileName = getParamsHelper('filename'); instanceMethodBuilder.define('getFileName',1); /** * Gets the header object of the upload * @function getHeaders * @instance * @memberof Upload * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'app.Upload() returns a 'Upload' instance * // 'blt212sample24a6b' is uid of an upload on Built.io Backend * var upload = Built.App('blt5d4sample2633b').Upload('blt212sample24a6b'); * upload.getHeaders(); * @return {object} */ module.exports.getHeaders = function(upload){ return upload.headers; } instanceMethodBuilder.define('getHeaders',1); module.exports.getURL = function(upload){ var Built = require('./built'); if(!getUid(upload)) return Built.App.getURL(upload.app)+"/uploads" else{ return Built.App.getURL(upload.app)+"/uploads/"+getUid(upload) } } instanceMethodBuilder.define('getURL',1); module.exports.getCombinedHeaders = function(upload) { var Built = require('./built'); return R.mixin(upload.headers, Built.App.getHeaders(upload.app)) // get headers from application and combine it with its own headers } instanceMethodBuilder.define('getCombinedHeaders',1); instanceMethodBuilder.define('getHeaders',1); function getData(upload){ return upload.data; } function getParams(upload){ return upload.params; } function getRequestMethod(upload){ if(!getUid(upload)) return 'POST'; else{ return 'PUT'; } } function listener(event){ if(event.origin === "https://api.built.io"){ var data = (event.data?event.data:event.message); data = JSON.parse(data); var payloadNum = data.postmessage_payload; callbackTray[payloadNum](data); // execute the callback attached to give file upload delete callbackTray[payloadNum]; clearDom(payloadNum); // removed the iFrame and form elements from dom } } function attachPostMsgListener(){ if(window && typeof window.addEventListener){ window.addEventListener("message", listener, false); } else{ window.attachEvent("onmessage", listener); } } function clearDom(payloadNum){ var uploadForm = document.getElementById("builtUploadForm"+payloadNum); var iFrame = document.getElementById("builtIFrame" +payloadNum); uploadForm.parentNode.removeChild(uploadForm); iFrame.parentNode.removeChild(iFrame); } function uploadViaNode(upload){ if(utility.isString(getData(upload).file)) return readAndUploadFile(upload); else{ return uploadEncodedFile(getData(upload).encodedUpload, upload) } } function uploadEncodedFile(encodedUpload, upload){ var encodedUpload = getData(upload).encodedUpload; var param = { PARAM: { upload: getParams(upload) } }; return fileUploader.makePostRequest(encodedUpload.contentType, encodedUpload.name, encodedUpload.bytesData, param, constants.UPLOAD_KEY_NAME, upload) .then(function (response) { var parsedResponse = JSON.parse(response); return uploadCons(upload.app,upload.headers,parsedResponse.upload,parsedResponse.upload.uid); }) } function readAndUploadFile(upload){ var fileExtension = /\.([^.]*)$/.exec(getData(upload).file); if (fileExtension) { fileExtension = fileExtension[1].toLowerCase(); } var playLoad = getUploadPayload(upload); var contentType = constants.MIME_TYPES[fileExtension]; var fileName = path.basename(playLoad); var fileData = fs.readFileSync(playLoad); var param = { PARAM: { upload: getParams(upload) } }; return fileUploader.makePostRequest(contentType, fileName, fileData, param, constants.UPLOAD_KEY_NAME, upload) .then(function (response) { var parsedResponse = JSON.parse(response); return uploadCons(upload.app,upload.headers,parsedResponse.upload,parsedResponse.upload.uid); }) } //return promise module.exports.getHttpRequestOptions = function(upload){ var url = module.exports.getURL(upload); var hostname = ''; var path = ''; var method = 'POST' if(upload.getUid()){ method = 'PUT' } if(url.substr(0,7) === 'http://'){ hostname = url.split('http://')[1].split(':')[0]; } else if(url.substr(0,8) === 'https://'){ hostname = url.split('https://')[1].split(':')[0]; } var pathArray = url.split('https://')[1].split(':')[1].split('/'); for (var count = 1; count < pathArray.length; count++) { // adds /v1/uploads or /v1/uploads/(uid) path += '/'+pathArray[count]; } return{ host : hostname, path : path, method : method, encoding :'utf8' } } instanceMethodBuilder.define('getHttpRequestOptions',1); function uploadViaIFramePosting(upload){ var cloneElm = getUploadPayload(upload).cloneNode(); // check method getUploadPayload(upload).style.display = "none"; getUploadPayload(upload).parentNode.insertBefore(cloneElm,getUploadPayload(upload)); var uploadNum = Math.floor(Math.random()*1000); var deferred = when.defer(); callbackTray[uploadNum] = function(res) { if (res.upload) { // res consist of upload means the response was successfull Events.trigger("upload:end"); deferred.resolve(uploadCons(upload.app, upload.headers, res.upload, res.upload.uid)); } else { deferred.reject(res); } }; var iFrame = fileUploader.createIFrame(uploadNum); var uploadForm = fileUploader.createUploadForm(module.exports.getURL(upload),module.exports.getCombinedHeaders(upload),getRequestMethod(upload),JSON.stringify({ upload:getParams(upload) }),getUploadPayload(upload),constants.UPLOAD_KEY_NAME, uploadNum); document.body.appendChild(iFrame); document.body.appendChild(uploadForm); Events.trigger("upload:start"); uploadForm.submit(); return deferred.promise; }