Skip to content

Commit cee2d26

Browse files
committed
Refactor files.js into FilesController.
1 parent 67959e5 commit cee2d26

File tree

4 files changed

+103
-102
lines changed

4 files changed

+103
-102
lines changed

src/FilesAdapter.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,12 @@
1111
// and for the API server to be using the ExportAdapter
1212
// database adapter.
1313

14-
let adapter = null;
15-
16-
export function setAdapter(filesAdapter) {
17-
adapter = filesAdapter;
18-
}
19-
20-
export function getAdapter() {
21-
return adapter;
22-
}
23-
2414
export class FilesAdapter {
2515
createFileAsync(config, filename, data) { }
2616

2717
getFileDataAsync(config, filename) { }
2818

2919
getFileLocation(config, request, filename) { }
3020
}
21+
22+
export default FilesAdapter;

src/FilesController.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// files.js
2+
3+
var bodyParser = require('body-parser'),
4+
Config = require('./Config'),
5+
express = require('express'),
6+
middlewares = require('./middlewares.js'),
7+
mime = require('mime'),
8+
Parse = require('parse/node').Parse,
9+
rack = require('hat').rack();
10+
11+
export class FilesController {
12+
constructor(filesAdapter) {
13+
this._filesAdapter = filesAdapter;
14+
}
15+
16+
getHandler() {
17+
return (req, res) => {
18+
let config = new Config(req.params.appId);
19+
this._filesAdapter.getFileDataAsync(config, req.params.filename).then((data) => {
20+
res.status(200);
21+
var contentType = mime.lookup(req.params.filename);
22+
res.set('Content-type', contentType);
23+
res.end(data);
24+
}).catch((error) => {
25+
res.status(404);
26+
res.set('Content-type', 'text/plain');
27+
res.end('File not found.');
28+
});
29+
};
30+
}
31+
32+
createHandler() {
33+
return (req, res, next) => {
34+
if (!req.body || !req.body.length) {
35+
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
36+
'Invalid file upload.'));
37+
return;
38+
}
39+
40+
if (req.params.filename.length > 128) {
41+
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
42+
'Filename too long.'));
43+
return;
44+
}
45+
46+
if (!req.params.filename.match(/^[_a-zA-Z0-9][a-zA-Z0-9@\.\ ~_-]*$/)) {
47+
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
48+
'Filename contains invalid characters.'));
49+
return;
50+
}
51+
52+
// If a content-type is included, we'll add an extension so we can
53+
// return the same content-type.
54+
let extension = '';
55+
let hasExtension = req.params.filename.indexOf('.') > 0;
56+
let contentType = req.get('Content-type');
57+
if (!hasExtension && contentType && mime.extension(contentType)) {
58+
extension = '.' + mime.extension(contentType);
59+
}
60+
61+
let filename = rack() + '_' + req.params.filename + extension;
62+
this._filesAdapter.createFileAsync(req.config, filename, req.body).then(() => {
63+
res.status(201);
64+
var location = this._filesAdapter.getFileLocation(req.config, req, filename);
65+
res.set('Location', location);
66+
res.json({ url: location, name: filename });
67+
}).catch((error) => {
68+
console.log(error);
69+
next(new Parse.Error(Parse.Error.FILE_SAVE_ERROR,
70+
'Could not store file.'));
71+
});
72+
};
73+
}
74+
75+
getExpressRouter() {
76+
let router = express.Router();
77+
router.get('/files/:appId/:filename', this.getHandler());
78+
79+
router.post('/files', function(req, res, next) {
80+
next(new Parse.Error(Parse.Error.INVALID_FILE_NAME,
81+
'Filename not provided.'));
82+
});
83+
84+
router.post('/files/:filename',
85+
middlewares.allowCrossDomain,
86+
bodyParser.raw({type: '*/*', limit: '20mb'}),
87+
middlewares.handleParseHeaders,
88+
this.createHandler()
89+
);
90+
91+
return router;
92+
}
93+
}
94+
95+
export default FilesController;

src/files.js

Lines changed: 0 additions & 85 deletions
This file was deleted.

src/index.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ var batch = require('./batch'),
1212
PromiseRouter = require('./PromiseRouter'),
1313
httpRequest = require('./httpRequest');
1414

15-
import { setAdapter as setFilesAdapter } from './FilesAdapter';
1615
import { default as GridStoreAdapter } from './GridStoreAdapter';
16+
import { default as FilesController } from './FilesController';
1717

1818
// Mutate the Parse object to add the Cloud Code handlers
1919
addParseCloud();
@@ -48,11 +48,9 @@ function ParseServer(args) {
4848
if (args.databaseAdapter) {
4949
DatabaseAdapter.setAdapter(args.databaseAdapter);
5050
}
51-
if (args.filesAdapter) {
52-
setFilesAdapter(args.filesAdapter);
53-
} else {
54-
setFilesAdapter(new GridStoreAdapter());
55-
}
51+
52+
let filesAdapter = args.filesAdapter || new GridStoreAdapter();
53+
5654
if (args.databaseURI) {
5755
DatabaseAdapter.setAppDatabaseURI(args.appId, args.databaseURI);
5856
}
@@ -95,7 +93,8 @@ function ParseServer(args) {
9593
var api = express();
9694

9795
// File handling needs to be before default middlewares are applied
98-
api.use('/', require('./files').router);
96+
let filesController = new FilesController(filesAdapter);
97+
api.use('/', filesController.getExpressRouter());
9998

10099
// TODO: separate this from the regular ParseServer object
101100
if (process.env.TESTING == 1) {

0 commit comments

Comments
 (0)