ali-flmngr-server-fixed
Version:
> Node.js Backend for Flmngr file manager
469 lines (452 loc) • 23.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const Message_1 = require("../models/Message");
const utils_1 = require("../utils");
const { nanoid } = require('nanoid');
const { readdirSync, renameSync } = require("fs");
const mmm = require('mmmagic');
const magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE);
class FMController {
constructor(_fmRepository, _rootDirPath) {
this._fmRepository = _fmRepository;
this._rootDirPath = _rootDirPath;
this._cacheDirName = 'cache';
this._checkPathStartsWithRoot = (pathTo) => pathTo.startsWith(this._rootDirPath);
this._toAbsolutePath = (dirPath) =>
path_1.default.join(this._rootDirPath, ...path_1.default
.join(...dirPath.split('/'))
.split(path_1.default.sep)
.slice(1));
this._sendError = (res, code, args = null) => {
res.json({
data: null,
error: {
args,
code,
files: null,
},
});
};
this.getVersion = (_, res) => __awaiter(this, void 0, void 0, function* () {
res.json({ error: null, data: { version: 1, language: 'typescript' } });
});
this.dirList = (_, res) => __awaiter(this, void 0, void 0, function* () {
let isDirExists = fs_1.default.existsSync(this._rootDirPath) && fs_1.default.lstatSync(this._rootDirPath).isDirectory();
if (!isDirExists) {
return this._sendError(res, Message_1.FMErrorMessage.ROOT_DIR_DOES_NOT_EXIST);
}
const dirList = yield this._fmRepository.getDirectories(this._rootDirPath);
const pathToCut = path_1.default.dirname(this._rootDirPath);
const data = (yield Promise.all(dirList.map((dirPath) => __awaiter(this, void 0, void 0, function* () {
if (dirPath.includes(path_1.default.join(this._rootDirPath, this._cacheDirName)) ||
dirPath.includes(path_1.default.join(this._rootDirPath, 'tmp'))) {
return;
}
return {
f: yield this._fmRepository.countFiles(dirPath),
d: yield this._fmRepository.countDirectories(dirPath),
p: dirPath
.replace(pathToCut, '')
.split(path_1.default.sep)
.join('/'),
};
})))).filter((item) => Boolean(item)); // Для фильтрации вырезанных папок
res.json({ error: null, data });
});
this.dirCreate = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { d: dirPath, n: name } = req.body;
if (utils_1.areThereForbiddenCharacters(name)) {
return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS);
}
const absPath = this._toAbsolutePath(dirPath);
if (!this._checkPathStartsWithRoot(absPath)) {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY);
}
try {
yield this._fmRepository.createDirectory(absPath, name);
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY);
}
});
this.dirRename = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { d: dirPath, n: name } = req.body;
if (utils_1.areThereForbiddenCharacters(name)) {
return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS);
}
const absPath = this._toAbsolutePath(dirPath);
if (!this._checkPathStartsWithRoot(absPath)) {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY);
}
try {
yield this._fmRepository.renameDirectory(absPath, name);
res.json({ data: true, error: null });
}
catch (error) {
if (['ENOTEMPTY', 'EEXIST', 'EPERM', 'EACCES'].includes(error.code)) {
return this._sendError(res, Message_1.FMErrorMessage.FILE_ALREADY_EXISTS, [name]);
}
this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME);
}
});
this.dirDelete = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { d: dirPath } = req.body;
const absPath = this._toAbsolutePath(dirPath);
if (absPath === this._rootDirPath || !this._checkPathStartsWithRoot(absPath)) {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_DIRECTORY);
}
try {
yield this._fmRepository.removeDirectory(absPath);
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_DIRECTORY);
}
});
this.dirCopy = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { d: dirPath, n: newPath } = req.body;
const absDirPath = this._toAbsolutePath(dirPath);
const absNewPath = this._toAbsolutePath(newPath);
if (!this._checkPathStartsWithRoot(absDirPath) ||
!this._checkPathStartsWithRoot(absNewPath)) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
try {
yield this._fmRepository.copyDirectory(absDirPath, path_1.default.join(absNewPath, utils_1.getTitle(dirPath)));
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES);
}
});
this.dirMove = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { d: dirPath, n: newPath } = req.body;
const absDirPath = this._toAbsolutePath(dirPath);
const absNewPath = this._toAbsolutePath(newPath);
if (!this._checkPathStartsWithRoot(absDirPath) ||
!this._checkPathStartsWithRoot(absNewPath)) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
try {
yield this._fmRepository.moveDirectory(absDirPath, path_1.default.join(absNewPath, utils_1.getTitle(dirPath)));
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
});
this.dirDownload = (req, res) => __awaiter(this, void 0, void 0, function* () {
let { d: dirPath } = req.query;
const dirAbsolutePath = this._toAbsolutePath(dirPath);
if (!this._fmRepository.isDirectoryOrFileExists(dirAbsolutePath) ||
!this._checkPathStartsWithRoot(dirAbsolutePath)) {
res.sendStatus(404);
return;
}
if (typeof (dirPath) != "string") {
dirPath = '0';
}
res.attachment(`${utils_1.getTitle(dirPath)}.zip`);
try {
yield this._fmRepository.downloadDirectory(dirAbsolutePath, res);
}
catch (e) {
res.sendStatus(500);
}
});
this.fileListPaged = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { dir: dirPath } = req.body;
const absDirPath = this._toAbsolutePath(dirPath);
if (!this._checkPathStartsWithRoot(absDirPath)) {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_CREATE_DIRECTORY);
}
if (!(yield this._fmRepository.isDirectoryOrFileExists(absDirPath))) {
return this._sendError(res, Message_1.FMErrorMessage.DIR_DOES_NOT_EXIST, [dirPath]);
}
try {
const fileListPaged = yield this._fmRepository.getFiles(absDirPath);
const files = yield Promise.all(fileListPaged.map((filePath) => __awaiter(this, void 0, void 0, function* () {
return ({
name: yield this._fmRepository.getName(filePath),
size: yield this._fmRepository.getFileSize(filePath),
timestamp: yield this._fmRepository.getFileCreationTime(filePath),
width: yield this._fmRepository.getFileWidth(filePath),
height: yield this._fmRepository.getFileHeight(filePath),
blurHash: yield this._fmRepository.getFileBlurHash(filePath),
formats: [],
});
})));
let data = { files, isEnd: true };
res.json({ error: null, data: data });
}
catch (error) {
return this._sendError(res, Message_1.FMErrorMessage.DIR_CANNOT_BE_READ);
}
});
this.fileDelete = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { fs: filePaths } = req.body;
const filePathsList = filePaths.split('|');
if (filePathsList.some((filePath) => {
const absPath = this._toAbsolutePath(filePath);
return !this._fmRepository.isDirectoryOrFileExists(absPath) ||
!this._checkPathStartsWithRoot(absPath);
})) {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_FILE, filePathsList.map(utils_1.getLastDir));
}
try {
yield Promise.all(filePathsList.map((filePath) => {
this._fmRepository.removeFile(this._toAbsolutePath(filePath));
}));
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_DELETE_FILE);
}
});
this.fileCopy = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { fs: filePaths, n: newPath } = req.body;
const filePathsList = filePaths.split('|');
if (filePathsList.some((filePath) => {
const absPath = this._toAbsolutePath(filePath);
return !this._fmRepository.isDirectoryOrFileExists(absPath) ||
!this._checkPathStartsWithRoot(absPath);
})) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES);
}
const absNewPath = this._toAbsolutePath(newPath);
if (!this._checkPathStartsWithRoot(absNewPath)) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES);
}
try {
yield Promise.all(filePaths.split('|').map((filePath) => (this._fmRepository.copyFile(this._toAbsolutePath(filePath), path_1.default.join(absNewPath, utils_1.getLastDir(filePath))))));
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_COPYING_FILES);
}
});
this.fileRename = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { f: filePath, n: name } = req.body;
if (utils_1.areThereForbiddenCharacters(utils_1.getFileNameWithoutExt(name))) {
return this._sendError(res, Message_1.FMErrorMessage.DIR_NAME_CONTAINS_INVALID_SYMBOLS);
}
if (utils_1.getFileNameWithoutExt(name) === '') {
return this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME);
}
const absFilePath = this._toAbsolutePath(filePath);
if ((yield this._fmRepository.isDirectoryOrFileExists(utils_1.getPathWithNewName(absFilePath, name))) || !this._checkPathStartsWithRoot(absFilePath)) {
return this._sendError(res, Message_1.FMErrorMessage.FILE_ALREADY_EXISTS, [name]);
}
try {
yield this._fmRepository.renameFile(absFilePath, name);
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.UNABLE_TO_RENAME);
}
});
this.fileMove = (req, res) => __awaiter(this, void 0, void 0, function* () {
const { fs: filePaths, n: newPath } = req.body;
const filePathsList = filePaths.split('|');
const absNewPath = this._toAbsolutePath(newPath);
if (!this._checkPathStartsWithRoot(absNewPath)) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
if (filePathsList.some((filePath) => {
const absPath = this._toAbsolutePath(filePath);
return !this._fmRepository.isDirectoryOrFileExists(absPath) ||
!this._checkPathStartsWithRoot(absPath);
})) {
return this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
try {
yield Promise.all(filePathsList.map((filePath) => {
this._fmRepository.moveFile(this._toAbsolutePath(filePath), path_1.default.join(this._toAbsolutePath(newPath), utils_1.getLastDir(filePath)));
}));
res.json({ data: true, error: null });
}
catch (error) {
this._sendError(res, Message_1.FMErrorMessage.ERROR_ON_MOVING_FILES);
}
});
this.fileOriginal = (req, res) => __awaiter(this, void 0, void 0, function* () {
let { f: filePath } = req.body;
const fileAbsolutePath = this._toAbsolutePath(filePath);
if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath) ||
!this._checkPathStartsWithRoot(fileAbsolutePath)) {
res.sendStatus(404);
return;
}
try {
if (typeof (filePath) != "string") {
filePath = '0';
}
const ext = path_1.default.extname(filePath);
if (ext !== '.gif' && ext !== '.PNG' && ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg' && ext !== '.webp' && ext !== '.JPG' && ext !== '.JPEG') {
res.sendStatus(415);
return;
}
res.setHeader('Content-Type', `image/${ext.replace('.', '')}`);
res.setHeader('Content-Length', yield this._fmRepository.getFileSize(fileAbsolutePath));
res.send(yield this._fmRepository.getImageOriginal(fileAbsolutePath));
}
catch (error) {
res.sendStatus(500);
}
});
this.filePreview = (req, res) => __awaiter(this, void 0, void 0, function* () {
let { f: filePath, width: width } = req.body;
let name = yield this._fmRepository.getName(filePath);
let LengthOfName = (name.length + 1) * -1;
let filedir = String(filePath).slice(0, LengthOfName);
const fileAbsolutePath = this._toAbsolutePath(filedir);
if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath) ||
!this._checkPathStartsWithRoot(fileAbsolutePath)) {
res.sendStatus(404);
return;
}
try {
if (!this._fmRepository.isDirectoryOrFileExists(fileAbsolutePath)) {
res.sendStatus(404);
return;
}
if (typeof (filePath) != "string") {
filePath = '0';
}
const ext = path_1.default.extname(filePath);
if (ext !== '.gif' && ext !== '.PNG' && ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg' && ext !== '.webp' && ext !== '.JPG' && ext !== '.JPEG') {
res.sendStatus(415);
return;
}
if (typeof (width) != "string") {
width = '0';
}
res.setHeader('Content-Type', `image/${ext.replace('.', '')}`);
res.setHeader('Content-Length', yield this._fmRepository.getFileSize(fileAbsolutePath));
res.send(yield this._fmRepository.getImagePreview(name, fileAbsolutePath, parseInt(width), path_1.default.join(this._rootDirPath, this._cacheDirName)));
}
catch (error) {
res.sendStatus(500);
}
});
this.fileUpload = (req, res) => __awaiter(this, void 0, void 0, function* () {
let { data } = req.body
data = JSON.parse(data);
const { action, uplaodId } = data;
if (action == 'uploadInit') {
return res.send({
"uploadId": nanoid(10),
"settings": { "maxImageResizeWidth": 5000, "maxImageResizeHeight": 5000 },
"ok": true
});
}
if (action === 'uploadAddFile') {
const imageMimeTypes = ["image/tiff", "image/svg+xml", "image/png", "image/jpeg", "image/vnd.microsoft.icon", "image/gif", "image/bmp", "image/webp"];
const isImage = imageMimeTypes.includes(req.file.mimetype);
let width = null, height = null;
if (isImage) {
width = yield this._fmRepository.getFileWidth(req.file.path);
height = yield this._fmRepository.getFileHeight(req.file.path);
}
return res.send({
file: {
"isCommited": false,
"name": req.file.filename,
"dir": `${uplaodId}/`,
"bytes": req.file.size,
isImage,
width,
height,
"errors": [],
"sizes": []
},
ok: true
});
}
if (action == 'uploadCommit') {
let { dir } = data;
const folderPath = path_1.default.resolve(this._rootDirPath, '../tempFile');
const files = [], files2 = [];
// make response obj
for (const file of readdirSync(folderPath)) {
const filePath = `${folderPath}/${file}`;
const { isImage, width, height } = this.isFileImage(filePath, yield this.getFileMimeType(filePath));
const fileSize = yield this._fmRepository.getFileSize(filePath);
let name = file;
dir = `/${dir}/`;
let destPath = this._rootDirPath + dir + name;
if(fs_1.default.existsSync(destPath)) {
name = `${Date.now()}-${file}`;
destPath = this._rootDirPath + dir + name;
}
fs_1.default.renameSync(filePath, destPath);
files.push({
isCommited: true,
name,
dir,
bytes: fileSize,
isImage,
width,
height,
errors: [],
sizes: []
});
files2.push({
name,
size: fileSize,
timestamp: Date.now(),
width,
height,
blurHash: null,
formats: []
});
}
res.send({
files,
files2,
ok: true,
});
}
});
this.isFileImage = (filePath, mimytype) => __awaiter(this, void 0, void 0, function* () {
const imageMimeTypes = ["image/tiff", "image/svg+xml", "image/png", "image/jpeg", "image/vnd.microsoft.icon", "image/gif", "image/bmp", "image/webp"];
return {
isImage: imageMimeTypes.includes(mimytype),
width: yield this._fmRepository.getFileWidth(filePath),
height: yield this._fmRepository.getFileHeight(filePath)
}
});
this.fileListSpecified = (req, res) => __awaiter(this, void 0, void 0, function* () {
let response = {
"error": null,
"data": []
};
return res.json(response);
});
this.getFileMimeType = (filePath) => __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
magic.detectFile(filePath, (error, result) => {
if (error) return reject(error);
resolve(result);
});
});
});
}
}
exports.default = FMController;
//# sourceMappingURL=FMController.js.map