Merge pull request #330 from ParsePlatform/nlutsenko.es6.adapters

Refactor files.js into FilesController.
This commit is contained in:
Nikita Lutsenko
2016-02-09 15:02:13 -08:00
4 changed files with 105 additions and 102 deletions

View File

@@ -0,0 +1,97 @@
// FilesController.js
import express from 'express';
import mime from 'mime';
import { Parse } from 'parse/node';
import BodyParser from 'body-parser';
import hat from 'hat';
import * as Middlewares from '../middlewares';
import Config from '../Config';
const rack = hat.rack();
export class FilesController {
constructor(filesAdapter) {
this._filesAdapter = filesAdapter;
}
getHandler() {
return (req, res) => {
let config = new Config(req.params.appId);
this._filesAdapter.getFileDataAsync(config, req.params.filename).then((data) => {
res.status(200);
var contentType = mime.lookup(req.params.filename);
res.set('Content-type', contentType);
res.end(data);
}).catch((error) => {
res.status(404);
res.set('Content-type', 'text/plain');
res.end('File not found.');
});
};
}
createHandler() {
return (req, res, next) => {
if (!req.body || !req.body.length) {
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
'Invalid file upload.'));
return;
}
if (req.params.filename.length > 128) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename too long.'));
return;
}
if (!req.params.filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename contains invalid characters.'));
return;
}
// If a content-type is included, we'll add an extension so we can
// return the same content-type.
let extension = '';
let hasExtension = req.params.filename.indexOf('.') > 0;
let contentType = req.get('Content-type');
if (!hasExtension && contentType && mime.extension(contentType)) {
extension = '.' + mime.extension(contentType);
}
let filename = rack() + '_' + req.params.filename + extension;
this._filesAdapter.createFileAsync(req.config, filename, req.body).then(() => {
res.status(201);
var location = this._filesAdapter.getFileLocation(req.config, req, filename);
res.set('Location', location);
res.json({ url: location, name: filename });
}).catch((error) => {
console.log(error);
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
'Could not store file.'));
});
};
}
getExpressRouter() {
let router = express.Router();
router.get('/files/:appId/:filename', this.getHandler());
router.post('/files', function(req, res, next) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename not provided.'));
});
router.post('/files/:filename',
Middlewares.allowCrossDomain,
BodyParser.raw({type: '*/*', limit: '20mb'}),
Middlewares.handleParseHeaders,
this.createHandler()
);
return router;
}
}
export default FilesController;

View File

@@ -11,16 +11,6 @@
// and for the API server to be using the ExportAdapter
// database adapter.
let adapter = null;
export function setAdapter(filesAdapter) {
adapter = filesAdapter;
}
export function getAdapter() {
return adapter;
}
export class FilesAdapter {
createFileAsync(config, filename, data) { }
@@ -28,3 +18,5 @@ export class FilesAdapter {
getFileLocation(config, request, filename) { }
}
export default FilesAdapter;

View File

@@ -1,85 +0,0 @@
// files.js
var bodyParser = require('body-parser'),
Config = require('./Config'),
express = require('express'),
middlewares = require('./middlewares.js'),
mime = require('mime'),
Parse = require('parse/node').Parse,
rack = require('hat').rack();
import { getAdapter as getFilesAdapter } from './FilesAdapter';
var router = express.Router();
var processCreate = function(req, res, next) {
if (!req.body || !req.body.length) {
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
'Invalid file upload.'));
return;
}
if (req.params.filename.length > 128) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename too long.'));
return;
}
if (!req.params.filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename contains invalid characters.'));
return;
}
// If a content-type is included, we'll add an extension so we can
// return the same content-type.
var extension = '';
var hasExtension = req.params.filename.indexOf('.') > 0;
var contentType = req.get('Content-type');
if (!hasExtension && contentType && mime.extension(contentType)) {
extension = '.' + mime.extension(contentType);
}
var filename = rack() + '_' + req.params.filename + extension;
getFilesAdapter().createFileAsync(req.config, filename, req.body).then(() => {
res.status(201);
var location = getFilesAdapter().getFileLocation(req.config, req, filename);
res.set('Location', location);
res.json({ url: location, name: filename });
}).catch((error) => {
console.log(error);
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
'Could not store file.'));
});
};
var processGet = function(req, res) {
var config = new Config(req.params.appId);
getFilesAdapter().getFileDataAsync(config, req.params.filename).then((data) => {
res.status(200);
var contentType = mime.lookup(req.params.filename);
res.set('Content-type', contentType);
res.end(data);
}).catch((error) => {
res.status(404);
res.set('Content-type', 'text/plain');
res.end('File not found.');
});
};
router.get('/files/:appId/:filename', processGet);
router.post('/files', function(req, res, next) {
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
'Filename not provided.'));
});
router.post('/files/:filename',
middlewares.allowCrossDomain,
bodyParser.raw({type: '*/*', limit: '20mb'}),
middlewares.handleParseHeaders,
processCreate);
module.exports = {
router: router
};

View File

@@ -12,8 +12,8 @@ var batch = require('./batch'),
PromiseRouter = require('./PromiseRouter'),
httpRequest = require('./httpRequest');
import { setAdapter as setFilesAdapter } from './FilesAdapter';
import { default as GridStoreAdapter } from './GridStoreAdapter';
import { default as FilesController } from './Controllers/FilesController';
// Mutate the Parse object to add the Cloud Code handlers
addParseCloud();
@@ -48,11 +48,9 @@ function ParseServer(args) {
if (args.databaseAdapter) {
DatabaseAdapter.setAdapter(args.databaseAdapter);
}
if (args.filesAdapter) {
setFilesAdapter(args.filesAdapter);
} else {
setFilesAdapter(new GridStoreAdapter());
}
let filesAdapter = args.filesAdapter || new GridStoreAdapter();
if (args.databaseURI) {
DatabaseAdapter.setAppDatabaseURI(args.appId, args.databaseURI);
}
@@ -95,7 +93,8 @@ function ParseServer(args) {
var api = express();
// File handling needs to be before default middlewares are applied
api.use('/', require('./files').router);
let filesController = new FilesController(filesAdapter);
api.use('/', filesController.getExpressRouter());
// TODO: separate this from the regular ParseServer object
if (process.env.TESTING == 1) {