Skip to content

Refactor files.js into FilesController. #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions src/Controllers/FilesController.js
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 2 additions & 10 deletions src/FilesAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,12 @@
// 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) { }

getFileDataAsync(config, filename) { }

getFileLocation(config, request, filename) { }
}

export default FilesAdapter;
85 changes: 0 additions & 85 deletions src/files.js

This file was deleted.

13 changes: 6 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down