You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/src/file.js

154 lines
3.9 KiB
JavaScript

8 years ago
'use strict';
11 years ago
const fs = require('fs');
const nconf = require('nconf');
const path = require('path');
const winston = require('winston');
const mkdirp = require('mkdirp');
const mime = require('mime');
const graceful = require('graceful-fs');
const slugify = require('./slugify');
graceful.gracefulify(fs);
const file = module.exports;
file.saveFileToLocal = async function (filename, folder, tempPath) {
/*
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
*/
filename = filename.split('.').map(name => slugify(name)).join('.');
const uploadPath = path.join(nconf.get('upload_path'), folder, filename);
if (!uploadPath.startsWith(nconf.get('upload_path'))) {
throw new Error('[[error:invalid-path]]');
}
winston.verbose(`Saving file ${filename} to : ${uploadPath}`);
await mkdirp(path.dirname(uploadPath));
await fs.promises.copyFile(tempPath, uploadPath);
return {
url: `/assets/uploads/${folder ? `${folder}/` : ''}${filename}`,
path: uploadPath,
};
11 years ago
};
file.base64ToLocal = async function (imageData, uploadPath) {
const buffer = Buffer.from(imageData.slice(imageData.indexOf('base64') + 7), 'base64');
uploadPath = path.join(nconf.get('upload_path'), uploadPath);
await fs.promises.writeFile(uploadPath, buffer, {
encoding: 'base64',
});
return uploadPath;
};
// https://stackoverflow.com/a/31205878/583363
file.appendToFileName = function (filename, string) {
const dotIndex = filename.lastIndexOf('.');
if (dotIndex === -1) {
return filename + string;
}
return filename.substring(0, dotIndex) + string + filename.substring(dotIndex);
};
file.allowedExtensions = function () {
const meta = require('./meta');
let allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
if (!allowedExtensions) {
return [];
}
allowedExtensions = allowedExtensions.split(',');
allowedExtensions = allowedExtensions.filter(Boolean).map((extension) => {
extension = extension.trim();
if (!extension.startsWith('.')) {
extension = `.${extension}`;
}
8 years ago
return extension.toLowerCase();
});
if (allowedExtensions.includes('.jpg') && !allowedExtensions.includes('.jpeg')) {
allowedExtensions.push('.jpeg');
}
return allowedExtensions;
};
file.exists = async function (path) {
try {
await fs.promises.stat(path);
} catch (err) {
if (err.code === 'ENOENT') {
return false;
8 years ago
}
throw err;
}
return true;
9 years ago
};
file.existsSync = function (path) {
9 years ago
try {
8 years ago
fs.statSync(path);
} catch (err) {
if (err.code === 'ENOENT') {
return false;
}
throw err;
9 years ago
}
8 years ago
return true;
9 years ago
};
file.delete = async function (path) {
if (!path) {
return;
}
try {
await fs.promises.unlink(path);
} catch (err) {
winston.warn(err);
}
};
file.link = async function link(filePath, destPath, relative) {
if (relative && process.platform !== 'win32') {
filePath = path.relative(path.dirname(destPath), filePath);
}
if (process.platform === 'win32') {
await fs.promises.link(filePath, destPath);
} else {
await fs.promises.symlink(filePath, destPath, 'file');
}
};
file.linkDirs = async function linkDirs(sourceDir, destDir, relative) {
if (relative && process.platform !== 'win32') {
sourceDir = path.relative(path.dirname(destDir), sourceDir);
}
const type = (process.platform === 'win32') ? 'junction' : 'dir';
await fs.promises.symlink(sourceDir, destDir, type);
};
file.typeToExtension = function (type) {
let 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 = async function (dir) {
const subdirs = await fs.promises.readdir(dir);
const files = await Promise.all(subdirs.map(async (subdir) => {
const res = path.resolve(dir, subdir);
return (await fs.promises.stat(res)).isDirectory() ? file.walk(res) : res;
}));
return files.reduce((a, f) => a.concat(f), []);
};
Async refactor in place (#7736) * 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 cea206a9b8e6d8295310074b18cc82a504487862. * 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 :volcano: * feat: less returns * feat: more await rewrite * fix: redis tests * feat: convert sortedSetAdd rewrite psql transaction to async/await * feat: :dog: * 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
6 years ago
require('./promisify')(file);