mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-16 20:42:58 +01:00
* feat: allow both callback&and await
* feat: ignore async key
* feat: callbackify and promisify in same file
* Revert "feat: callbackify and promisify in same file"
This reverts commit cea206a9b8.
* feat: no need to store .callbackify
* feat: change getTopics to async
* feat: remove .async
* fix: byScore
* feat: rewrite topics/index and social with async/await
* fix: rewrite topics/data.js
fix issue with async.waterfall, only pass result if its not undefined
* feat: add callbackify to redis/psql
* feat: psql use await
* fix: redis 🌋
* feat: less returns
* feat: more await rewrite
* fix: redis tests
* feat: convert sortedSetAdd
rewrite psql transaction to async/await
* feat: 🐶
* feat: test
* feat: log client and query
* feat: log bind
* feat: more logs
* feat: more logs
* feat: check perform
* feat: dont callbackify transaction
* feat: remove logs
* fix: main functions
* feat: more logs
* fix: increment
* fix: rename
* feat: remove cls
* fix: remove console.log
* feat: add deprecation message to .async usage
* feat: update more dbal methods
* fix: redis :voodoo:
* feat: fix redis zrem, convert setObject
* feat: upgrade getObject methods
* fix: psql getObjectField
* fix: redis tests
* feat: getObjectKeys
* feat: getObjectValues
* feat: isObjectField
* fix: add missing return
* feat: delObjectField
* feat: incrObjectField
* fix: add missing await
* feat: remove exposed helpers
* feat: list methods
* feat: flush/empty
* feat: delete
* fix: redis delete all
* feat: get/set
* feat: incr/rename
* feat: type
* feat: expire
* feat: setAdd
* feat: setRemove
* feat: isSetMember
* feat: getSetMembers
* feat: setCount, setRemoveRandom
* feat: zcard,zcount
* feat: sortedSetRank
* feat: isSortedSetMember
* feat: zincrby
* feat: sortedSetLex
* feat: processSortedSet
* fix: add mising await
* feat: debug psql
* fix: psql test
* fix: test
* fix: another test
* fix: test fix
* fix: psql tests
* feat: remove logs
* feat: user arrow func
use builtin async promises
* feat: topic bookmarks
* feat: topic.delete
* feat: topic.restore
* feat: topics.purge
* feat: merge
* feat: suggested
* feat: topics/user.js
* feat: topics modules
* feat: topics/follow
* fix: deprecation msg
* feat: fork
* feat: topics/posts
* feat: sorted/recent
* feat: topic/teaser
* feat: topics/tools
* feat: topics/unread
* feat: add back node versions
disable deprecation notice
wrap async controllers in try/catch
* feat: use db directly
* feat: promisify in place
* fix: redis/psql
* feat: deprecation message
logs for psql
* feat: more logs
* feat: more logs
* feat: logs again
* feat: more logs
* fix: call release
* feat: restore travis, remove logs
* fix: loops
* feat: remove .async. usage
264 lines
5.7 KiB
JavaScript
264 lines
5.7 KiB
JavaScript
'use strict';
|
|
|
|
var fs = require('fs');
|
|
var nconf = require('nconf');
|
|
var path = require('path');
|
|
var winston = require('winston');
|
|
var mkdirp = require('mkdirp');
|
|
var mime = require('mime');
|
|
var graceful = require('graceful-fs');
|
|
|
|
var utils = require('./utils');
|
|
|
|
graceful.gracefulify(fs);
|
|
|
|
var file = module.exports;
|
|
|
|
/**
|
|
* Asynchronously copies `src` to `dest`
|
|
* @param {string} src - source filename to copy
|
|
* @param {string} dest - destination filename of the copy operation
|
|
* @param {function(Error): void} callback
|
|
*/
|
|
function copyFile(src, dest, callback) {
|
|
var calledBack = false;
|
|
|
|
var read;
|
|
var write;
|
|
|
|
function done(err) {
|
|
if (calledBack) {
|
|
return;
|
|
}
|
|
calledBack = true;
|
|
|
|
if (err) {
|
|
if (read) {
|
|
read.destroy();
|
|
}
|
|
if (write) {
|
|
write.destroy();
|
|
}
|
|
}
|
|
|
|
callback(err);
|
|
}
|
|
|
|
read = fs.createReadStream(src);
|
|
read.on('error', done);
|
|
|
|
write = fs.createWriteStream(dest);
|
|
write.on('error', done);
|
|
write.on('close', function () {
|
|
done();
|
|
});
|
|
|
|
read.pipe(write);
|
|
}
|
|
|
|
file.copyFile = (typeof fs.copyFile === 'function') ? fs.copyFile : copyFile;
|
|
|
|
file.saveFileToLocal = function (filename, folder, tempPath, callback) {
|
|
/*
|
|
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
|
|
*/
|
|
filename = filename.split('.').map(function (name) {
|
|
return utils.slugify(name);
|
|
}).join('.');
|
|
|
|
var uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
|
|
|
winston.verbose('Saving file ' + filename + ' to : ' + uploadPath);
|
|
mkdirp(path.dirname(uploadPath), function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
file.copyFile(tempPath, uploadPath, function (err) {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
callback(null, {
|
|
url: '/assets/uploads/' + (folder ? folder + '/' : '') + filename,
|
|
path: uploadPath,
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
file.base64ToLocal = function (imageData, uploadPath, callback) {
|
|
var buffer = Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
|
|
uploadPath = path.join(nconf.get('upload_path'), uploadPath);
|
|
|
|
fs.writeFile(uploadPath, buffer, {
|
|
encoding: 'base64',
|
|
}, function (err) {
|
|
callback(err, uploadPath);
|
|
});
|
|
};
|
|
|
|
file.isFileTypeAllowed = async function (path) {
|
|
var plugins = require('./plugins');
|
|
if (plugins.hasListeners('filter:file.isFileTypeAllowed')) {
|
|
return await plugins.fireHook('filter:file.isFileTypeAllowed', path);
|
|
}
|
|
const sharp = require('sharp');
|
|
await sharp(path, {
|
|
failOnError: true,
|
|
}).metadata();
|
|
};
|
|
|
|
// https://stackoverflow.com/a/31205878/583363
|
|
file.appendToFileName = function (filename, string) {
|
|
var dotIndex = filename.lastIndexOf('.');
|
|
if (dotIndex === -1) {
|
|
return filename + string;
|
|
}
|
|
return filename.substring(0, dotIndex) + string + filename.substring(dotIndex);
|
|
};
|
|
|
|
file.allowedExtensions = function () {
|
|
var meta = require('./meta');
|
|
var allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
|
|
if (!allowedExtensions) {
|
|
return [];
|
|
}
|
|
allowedExtensions = allowedExtensions.split(',');
|
|
allowedExtensions = allowedExtensions.filter(Boolean).map(function (extension) {
|
|
extension = extension.trim();
|
|
if (!extension.startsWith('.')) {
|
|
extension = '.' + extension;
|
|
}
|
|
return extension.toLowerCase();
|
|
});
|
|
|
|
if (allowedExtensions.includes('.jpg') && !allowedExtensions.includes('.jpeg')) {
|
|
allowedExtensions.push('.jpeg');
|
|
}
|
|
|
|
return allowedExtensions;
|
|
};
|
|
|
|
file.exists = function (path, callback) {
|
|
fs.stat(path, function (err) {
|
|
if (err) {
|
|
if (err.code === 'ENOENT') {
|
|
return callback(null, false);
|
|
}
|
|
return callback(err);
|
|
}
|
|
callback(null, true);
|
|
});
|
|
};
|
|
|
|
file.existsSync = function (path) {
|
|
try {
|
|
fs.statSync(path);
|
|
} catch (err) {
|
|
if (err.code === 'ENOENT') {
|
|
return false;
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
file.delete = function (path, callback) {
|
|
callback = callback || function () {};
|
|
if (!path) {
|
|
return setImmediate(callback);
|
|
}
|
|
fs.unlink(path, function (err) {
|
|
if (err) {
|
|
winston.warn(err);
|
|
}
|
|
callback();
|
|
});
|
|
};
|
|
|
|
file.link = function link(filePath, destPath, relative, callback) {
|
|
if (!callback) {
|
|
callback = relative;
|
|
relative = false;
|
|
}
|
|
|
|
if (relative && process.platform !== 'win32') {
|
|
filePath = path.relative(path.dirname(destPath), filePath);
|
|
}
|
|
|
|
if (process.platform === 'win32') {
|
|
fs.link(filePath, destPath, callback);
|
|
} else {
|
|
fs.symlink(filePath, destPath, 'file', callback);
|
|
}
|
|
};
|
|
|
|
file.linkDirs = function linkDirs(sourceDir, destDir, relative, callback) {
|
|
if (!callback) {
|
|
callback = relative;
|
|
relative = false;
|
|
}
|
|
|
|
if (relative && process.platform !== 'win32') {
|
|
sourceDir = path.relative(path.dirname(destDir), sourceDir);
|
|
}
|
|
|
|
var type = (process.platform === 'win32') ? 'junction' : 'dir';
|
|
fs.symlink(sourceDir, destDir, type, callback);
|
|
};
|
|
|
|
file.typeToExtension = function (type) {
|
|
var extension;
|
|
if (type) {
|
|
extension = '.' + mime.getExtension(type);
|
|
}
|
|
return extension;
|
|
};
|
|
|
|
// Adapted from http://stackoverflow.com/questions/5827612/node-js-fs-readdir-recursive-directory-search
|
|
file.walk = function (dir, done) {
|
|
var results = [];
|
|
|
|
fs.readdir(dir, function (err, list) {
|
|
if (err) {
|
|
return done(err);
|
|
}
|
|
var pending = list.length;
|
|
if (!pending) {
|
|
return done(null, results);
|
|
}
|
|
list.forEach(function (filename) {
|
|
filename = dir + '/' + filename;
|
|
fs.stat(filename, function (err, stat) {
|
|
if (err) {
|
|
return done(err);
|
|
}
|
|
|
|
if (stat && stat.isDirectory()) {
|
|
file.walk(filename, function (err, res) {
|
|
if (err) {
|
|
return done(err);
|
|
}
|
|
|
|
results = results.concat(res);
|
|
pending -= 1;
|
|
if (!pending) {
|
|
done(null, results);
|
|
}
|
|
});
|
|
} else {
|
|
results.push(filename);
|
|
pending -= 1;
|
|
if (!pending) {
|
|
done(null, results);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
require('./promisify')(file);
|