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