Source: controller/cloudupload.js

'use strict';

var path = require('path'),
	async = require('async'),
	fs = require('fs-extra'),
	formidable = require('formidable'),
	pkgcloud = require('pkgcloud'),
	Utilities = require('periodicjs.core.utilities'),
	ControllerHelper = require('periodicjs.core.controllerhelper'),
	Extensions = require('periodicjs.core.extensions'),
	cloudprovider,
	cloudproviderfilepath,
	cloudstorageclient,
	cloudStorageClientError,
	cloudStorageContainer,
	cloudStoragePublicPath,
	CoreExtension,
	CoreUtilities,
	CoreController,
	appSettings,
	mongoose,
	MediaAsset,
	logger;

/**
 * upload a document from a form upload, store it in your cloud provider storage, remove from server after moved to cloud service
 * @param  {object} req 
 * @param  {object} res 
 * @return {Function} next() callback
 */
var upload = function (req, res, next) {
	if (cloudStorageClientError) {
		CoreController.handleDocumentQueryErrorResponse({
			err: cloudStorageClientError,
			res: res,
			req: req
		});
	}
	else {
		// console.log('cloudprovider',cloudprovider);
		var form = new formidable.IncomingForm(),
			files = [],
			returnFile,
			returnFileObj = {},
			// fields = [],
			d = new Date(),
			clouddir = 'clouduploads/files/' + d.getUTCFullYear() + '/' + d.getUTCMonth() + '/' + d.getUTCDate(),
			uploadDirectory = '/public/' + clouddir,
			fullUploadDir = path.join(process.cwd(), uploadDirectory);
		req.controllerData = (req.controllerData) ? req.controllerData : {};

		form.keepExtensions = true;
		form.uploadDir = fullUploadDir;
		form.parse(req, function (err, fields, files) {
			// console.log(err, fields, files);
		});
		form.on('error', function (err) {
			logger.error(err);
			CoreController.handleDocumentQueryErrorResponse({
				err: err,
				res: res,
				req: req
			});
		});
		form.on('file', function (field, file) {
			returnFile = file;
			files.push(file);
		});
		form.on('end', function () {
			var newfilename = req.user._id.toString() + '-' + CoreUtilities.makeNiceName(path.basename(returnFile.name, path.extname(returnFile.name))) + path.extname(returnFile.name),
				newfilepath = path.join(clouddir, newfilename);


			cloudstorageclient.upload({
				container: cloudStorageContainer,
				remote: newfilepath,
				local: returnFile.path,
				headers: { // optionally provide raw headers to send to cloud files
					'Cache-Control': 'max-age=86400'
				}
			}, function (err, result) {
				//remove temp file
				fs.remove(returnFile.path, function (err) {
					if (err) {
						logger.error(err);
					}
					else {
						logger.silly('removing temp file', returnFile.path);
					}
				});

				if (err) {
					logger.error(err);
					CoreController.handleDocumentQueryErrorResponse({
						err: err,
						res: res,
						req: req
					});
				}
				else if (result) {
					returnFileObj.attributes = cloudStoragePublicPath;
					returnFileObj.size = returnFile.size;
					returnFileObj.filename = returnFile.name;
					returnFileObj.assettype = returnFile.type;
					returnFileObj.path = newfilepath;
					returnFileObj.locationtype = cloudprovider.provider;
					// returnFileObj.attributes.periodicDirectory = uploadDirectory;
					// returnFileObj.attributes.periodicPath = path.join(cloudStoragePublicPath.cdnUri,newfilepath);
					returnFileObj.fileurl = cloudStoragePublicPath.cdnUri + '/' + newfilepath;
					returnFileObj.attributes.periodicFilename = newfilename;
					returnFileObj.attributes.cloudfilepath = newfilepath;
					returnFileObj.attributes.cloudcontainername = cloudStorageContainer.name;
					// console.log('returnFileObj', returnFileObj);
					req.controllerData.fileData = returnFileObj;
					next();
				}
			});
		});
	}
};

/**
 * deletes file from cloud and removes document from mongo database
 * @param  {object} req 
 * @param  {object} res 
 */
var remove = function (req, res) {
	var asset = req.controllerData.asset;
	console.log('asset', asset);
	if (asset.locationtype === 'rackspace') {
		async.parallel({
			deletefile: function (callback) {
				cloudstorageclient.removeFile(asset.attributes.cloudcontainername, asset.attributes.cloudfilepath, callback);
			},
			removeasset: function (callback) {
				CoreController.deleteModel({
					model: MediaAsset,
					deleteid: asset._id,
					req: req,
					res: res,
					callback: callback
				});
			}
		}, function (err
			//, results
		) {
			if (err) {
				CoreController.handleDocumentQueryErrorResponse({
					err: err,
					res: res,
					req: req
				});
			}
			else {
				CoreController.handleDocumentQueryRender({
					req: req,
					res: res,
					redirecturl: '/p-admin/assets',
					responseData: {
						result: 'success',
						data: asset
					}
				});
			}
		});
	}
};

/**
 * create storage container from configuration in provider.json
 * @param  {object} req 
 * @param  {object} res 
 * @return {Function} next() callback
 */
var createStorageContainer = function () {
	fs.readJson(cloudproviderfilepath, function (err, data) {
		if (err) {
			cloudStorageClientError = err;
			logger.error(err);
		}
		else {
			try {
				cloudprovider = data[appSettings.application.environment];
				cloudstorageclient = pkgcloud.storage.createClient(cloudprovider);

				cloudstorageclient.createContainer({
						name: (cloudprovider.containername) ? cloudprovider.containername : 'periodicjs',
						type: 'public',
						metadata: {
							env: appSettings.application.environment,
							name: appSettings.name
						}
					},
					function (err, container) {
						if (err) {
							cloudStorageClientError = err;
							throw Error(err);
						}
						else {
							cloudStorageContainer = container;
							if (cloudprovider.provider === 'rackspace') {
								cloudstorageclient.setCdnEnabled(cloudStorageContainer, true, function (error, cont) {
									if (error) {
										cloudStorageClientError = error;
										throw Error(error);
									}
									else if (cont) {
										cloudStoragePublicPath = {
											cdnUri: cont.cdnUri,
											cdnSslUri: cont.cdnSslUri,
											cdnStreamingUri: cont.cdnStreamingUri,
											cdniOSUri: cont.cdniOSUri
										};
										// console.log('cont', cont);
										logger.silly('Successfully Created CDN Bucket');
									}
								});
							}
						}
					});
			}
			catch (e) {
				cloudStorageClientError = e;
				logger.error(e);
			}
		}
	});
};

/**
 * cloudupload controller
 * @module clouduploadController
 * @{@link https://github.com/typesettin/periodicjs.ext.clouduploads}
 * @author Yaw Joseph Etse
 * @copyright Copyright (c) 2014 Typesettin. All rights reserved.
 * @license MIT
 * @requires module:async
 * @requires module:path
 * @requires module:fs-extra
 * @requires module:formidable
 * @requires module:pkgcloud
 * @requires module:periodicjs.core.utilities
 * @requires module:periodicjs.core.controller
 * @requires module:periodicjs.core.extensions
 * @param  {object} resources variable injection from current periodic instance with references to the active logger and mongo session
 */
var controller = function (resources) {
	logger = resources.logger;
	mongoose = resources.mongoose;
	appSettings = resources.settings;
	CoreController = new ControllerHelper(resources);
	CoreUtilities = new Utilities(resources);
	CoreExtension = new Extensions(appSettings);
	MediaAsset = mongoose.model('Asset');
	cloudproviderfilepath = path.join(CoreExtension.getconfigdir({
		extname: 'periodicjs.ext.clouduploads'
	}), 'provider.json');
	// Collection = mongoose.model('Collection');
	// 
	// cdn files: https://github.com/pkgcloud/pkgcloud/issues/324
	// rackspace: https://gist.github.com/rdodev/129592b4addcebdf6ccd
	createStorageContainer();

	return {
		upload: upload,
		remove: remove
	};
};

module.exports = controller;