diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 3d225c22fe..60366be026 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -5,13 +5,14 @@ var async = require('async'); var nconf = require('nconf'); var validator = require('validator'); +var db = require('../database'); var meta = require('../meta'); var file = require('../file'); var plugins = require('../plugins'); var image = require('../image'); var privileges = require('../privileges'); -var uploadsController = {}; +var uploadsController = module.exports; uploadsController.upload = function (req, res, filesIterator) { var files = req.files.files; @@ -192,7 +193,7 @@ uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) { file.isFileTypeAllowed(uploadedFile.path, next); }, function (next) { - saveFileToLocal(uploadedFile, next); + saveFileToLocal(uid, uploadedFile, next); }, ], callback); }; @@ -220,27 +221,30 @@ uploadsController.uploadFile = function (uid, uploadedFile, callback) { return callback(new Error('[[error:invalid-file-type, ' + allowed.join(', ') + ']]')); } - saveFileToLocal(uploadedFile, callback); + saveFileToLocal(uid, uploadedFile, callback); }; -function saveFileToLocal(uploadedFile, callback) { +function saveFileToLocal(uid, uploadedFile, callback) { var filename = uploadedFile.name || 'upload'; var extension = path.extname(filename) || ''; filename = Date.now() + '-' + validator.escape(filename.substr(0, filename.length - extension.length)).substr(0, 255) + extension; - + var storedFile; async.waterfall([ function (next) { file.saveFileToLocal(filename, 'files', uploadedFile.path, next); }, function (upload, next) { - var storedFile = { + storedFile = { url: nconf.get('relative_path') + upload.url, path: upload.path, name: uploadedFile.name, }; - plugins.fireHook('filter:uploadStored', { uploadedFile: uploadedFile, storedFile: storedFile }, next); + db.sortedSetAdd('uid:' + uid + ':uploads', Date.now(), upload.url, next); + }, + function (next) { + plugins.fireHook('filter:uploadStored', { uid: uid, uploadedFile: uploadedFile, storedFile: storedFile }, next); }, function (data, next) { next(null, data.storedFile); @@ -254,5 +258,3 @@ function deleteTempFiles(files) { next(); }); } - -module.exports = uploadsController; diff --git a/src/file.js b/src/file.js index e31ae18399..2fbd15dbdf 100644 --- a/src/file.js +++ b/src/file.js @@ -141,8 +141,9 @@ file.exists = function (path, callback) { if (err.code === 'ENOENT') { return callback(null, false); } + return callback(err); } - callback(err, true); + callback(null, true); }); }; @@ -159,14 +160,17 @@ file.existsSync = function (path) { return true; }; -file.delete = function (path) { - if (path) { - fs.unlink(path, function (err) { - if (err) { - winston.error(err); - } - }); +file.delete = function (path, callback) { + callback = callback || function () {}; + if (!path) { + return callback(); } + fs.unlink(path, function (err) { + if (err) { + winston.error(err); + } + callback(); + }); }; file.link = function link(filePath, destPath, relative, callback) { diff --git a/src/user/delete.js b/src/user/delete.js index ace9dd969c..dd8e617903 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -2,6 +2,8 @@ var async = require('async'); var _ = require('lodash'); +var path = require('path'); +var nconf = require('nconf'); var db = require('../database'); var posts = require('../posts'); @@ -10,6 +12,7 @@ var groups = require('../groups'); var messaging = require('../messaging'); var plugins = require('../plugins'); var batch = require('../batch'); +var file = require('../file'); module.exports = function (User) { User.delete = function (callerUid, uid, callback) { @@ -24,6 +27,9 @@ module.exports = function (User) { function (next) { deleteTopics(callerUid, uid, next); }, + function (next) { + deleteUploads(uid, next); + }, function (next) { User.deleteAccount(uid, next); }, @@ -46,6 +52,22 @@ module.exports = function (User) { }, { alwaysStartAt: 0 }, callback); } + function deleteUploads(uid, callback) { + batch.processSortedSet('uid:' + uid + ':uploads', function (urls, next) { + async.waterfall([ + function (next) { + async.each(urls, function (url, next) { + var filePath = path.join(nconf.get('upload_path'), url.replace(nconf.get('upload_url'), '')); + file.delete(filePath, next); + }, next); + }, + function (next) { + db.sortedSetRemove('uid:' + uid + ':uploads', urls, next); + }, + ], next); + }, { alwaysStartAt: 0 }, callback); + } + User.deleteAccount = function (uid, callback) { var userData; async.waterfall([ diff --git a/test/uploads.js b/test/uploads.js index db8305d592..77fa0832ee 100644 --- a/test/uploads.js +++ b/test/uploads.js @@ -159,6 +159,41 @@ describe('Upload Controllers', function () { done(); }); }); + + it('should delete users uploads if account is deleted', function (done) { + var jar; + var uid; + var url; + var file = require('../src/file'); + + async.waterfall([ + function (next) { + user.create({ username: 'uploader', password: 'barbar' }, next); + }, + function (_uid, next) { + uid = _uid; + helpers.loginUser('uploader', 'barbar', next); + }, + function (jar, csrf_token, next) { + helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, next); + }, + function (res, body, next) { + assert(body); + assert(body[0].url); + url = body[0].url; + + user.delete(1, uid, next); + }, + function (next) { + var filePath = path.join(nconf.get('upload_path'), url.replace('/assets/uploads', '')); + file.exists(filePath, next); + }, + function (exists, next) { + assert(!exists); + done(); + }, + ], done); + }); }); describe('admin uploads', function () {