]> git.immae.eu Git - perso/Immae/Projets/Nodejs/Surfer.git/blame - src/files.js
Support recursive put
[perso/Immae/Projets/Nodejs/Surfer.git] / src / files.js
CommitLineData
ca2d3b4d
JZ
1'use strict';
2
3var fs = require('fs'),
4 path = require('path'),
5 ejs = require('ejs'),
6 rimraf = require('rimraf'),
8c3ae071 7 debug = require('debug')('files'),
eaa62184 8 mkdirp = require('mkdirp'),
ca2d3b4d
JZ
9 HttpError = require('connect-lastmile').HttpError,
10 HttpSuccess = require('connect-lastmile').HttpSuccess;
11
8c3ae071
JZ
12var gBasePath;
13
14exports = module.exports = function (basePath) {
15 gBasePath = basePath;
ca2d3b4d 16
8c3ae071
JZ
17 return {
18 get: get,
19 put: put,
20 del: del
21 };
22};
ca2d3b4d
JZ
23
24// http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js
25function copyFile(source, target, cb) {
26 var cbCalled = false;
27
eaa62184
JZ
28 // ensure directory
29 mkdirp(path.dirname(target), function (error) {
30 if (error) return cb(error);
ca2d3b4d 31
eaa62184
JZ
32 var rd = fs.createReadStream(source);
33 rd.on("error", function(err) {
34 done(err);
35 });
ca2d3b4d 36
eaa62184
JZ
37 var wr = fs.createWriteStream(target);
38 wr.on("error", function(err) {
39 done(err);
40 });
ca2d3b4d 41
eaa62184
JZ
42 wr.on("close", function(ex) {
43 done();
44 });
45
46 rd.pipe(wr);
ca2d3b4d 47
eaa62184
JZ
48 function done(err) {
49 if (!cbCalled) {
50 cb(err);
51 cbCalled = true;
52 }
ca2d3b4d 53 }
eaa62184 54 });
ca2d3b4d
JZ
55}
56
57function render(view, options) {
58 return ejs.render(fs.readFileSync(view, 'utf8'), options);
59}
60
61function getAbsolutePath(filePath) {
8c3ae071 62 var absoluteFilePath = path.resolve(gBasePath, filePath);
ca2d3b4d 63
8c3ae071 64 if (absoluteFilePath.indexOf(gBasePath) !== 0) return null;
ca2d3b4d
JZ
65 return absoluteFilePath;
66}
67
68function get(req, res, next) {
69 var filePath = req.params[0];
70 var absoluteFilePath = getAbsolutePath(filePath);
71 if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed'));
72
73 fs.stat(absoluteFilePath, function (error, result) {
74 if (error) return next(new HttpError(404, error));
75
8c3ae071 76 debug('get', absoluteFilePath);
ca2d3b4d
JZ
77
78 if (result.isFile()) return res.sendfile(absoluteFilePath);
79 if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) });
80
81 return next(new HttpError(500, 'unsupported type'));
82 });
83}
84
85function put(req, res, next) {
86 var filePath = req.params[0];
87
88 if (!req.files.file) return next(new HttpError(400, 'missing file'));
89
90 var absoluteFilePath = getAbsolutePath(filePath);
91 if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed'));
92
93 fs.stat(absoluteFilePath, function (error, result) {
94 if (error && error.code !== 'ENOENT') return next(new HttpError(500, error));
95
8c3ae071 96 debug('put', absoluteFilePath, req.files.file);
ca2d3b4d
JZ
97
98 if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories'));
99 if (!result || result.isFile()) {
100 return copyFile(req.files.file.path, absoluteFilePath, function (error) {
101 if (error) return next(new HttpError(500, error));
102 next(new HttpSuccess(201, {}));
103 });
104 }
105
106 return next(new HttpError(500, 'unsupported type'));
107 });
108}
109
110function del(req, res, next) {
111 var filePath = req.params[0];
112 var absoluteFilePath = getAbsolutePath(filePath);
eaa62184 113 if (!absoluteFilePath) return next(new HttpError(404, 'Not found'));
8c3ae071 114 if (absoluteFilePath.slice(gBasePath.length) === '') return next(new HttpError(403, 'Forbidden'));
ca2d3b4d
JZ
115
116 fs.stat(absoluteFilePath, function (error, result) {
117 if (error) return next(new HttpError(404, error));
118
119 rimraf(absoluteFilePath, function (error) {
120 if (error) return next(new HttpError(500, 'Unable to remove'));
a7f450d7 121 next(new HttpSuccess(200, {}));
ca2d3b4d
JZ
122 });
123 });
124}