built.io-browserify
Version:
SDK for Built.io Backend which is compatible with Browserify
747 lines (712 loc) • 23.7 kB
JavaScript
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;
}