| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- const logger = require('@alias/logger')('growi:service:fileUploaderLocal');
- const fs = require('fs');
- const path = require('path');
- const mkdir = require('mkdirp');
- const streamToPromise = require('stream-to-promise');
- const urljoin = require('url-join');
- module.exports = function(crowi) {
- const Uploader = require('./uploader');
- const lib = new Uploader(crowi);
- const basePath = path.posix.join(crowi.publicDir, 'uploads');
- function getFilePathOnStorage(attachment) {
- let filePath;
- if (attachment.filePath != null) { // backward compatibility for v3.3.x or below
- filePath = path.posix.join(basePath, attachment.filePath);
- }
- else {
- const dirName = (attachment.page != null)
- ? 'attachment'
- : 'user';
- filePath = path.posix.join(basePath, dirName, attachment.fileName);
- }
- return filePath;
- }
- lib.isValidUploadSettings = function() {
- return true;
- };
- lib.deleteFile = async function(attachment) {
- const filePath = getFilePathOnStorage(attachment);
- return lib.deleteFileByFilePath(filePath);
- };
- lib.deleteFiles = async function(attachments) {
- attachments.map((attachment) => {
- return this.deleteFile(attachment);
- });
- };
- lib.deleteFileByFilePath = async function(filePath) {
- // check file exists
- try {
- fs.statSync(filePath);
- }
- catch (err) {
- logger.warn(`Any AttachmentFile which path is '${filePath}' does not exist in local fs`);
- return;
- }
- return fs.unlinkSync(filePath);
- };
- lib.uploadFile = async function(fileStream, attachment) {
- logger.debug(`File uploading: fileName=${attachment.fileName}`);
- const filePath = getFilePathOnStorage(attachment);
- const dirpath = path.posix.dirname(filePath);
- // mkdir -p
- mkdir.sync(dirpath);
- const stream = fileStream.pipe(fs.createWriteStream(filePath));
- return streamToPromise(stream);
- };
- /**
- * Find data substance
- *
- * @param {Attachment} attachment
- * @return {stream.Readable} readable stream
- */
- lib.findDeliveryFile = async function(attachment) {
- const filePath = getFilePathOnStorage(attachment);
- // check file exists
- try {
- fs.statSync(filePath);
- }
- catch (err) {
- throw new Error(`Any AttachmentFile that relate to the Attachment (${attachment._id.toString()}) does not exist in local fs`);
- }
- // return stream.Readable
- return fs.createReadStream(filePath);
- };
- /**
- * check the file size limit
- *
- * In detail, the followings are checked.
- * - per-file size limit (specified by MAX_FILE_SIZE)
- */
- lib.checkLimit = async(uploadFileSize) => {
- const maxFileSize = crowi.configManager.getConfig('crowi', 'app:maxFileSize');
- const totalLimit = crowi.configManager.getConfig('crowi', 'app:fileUploadTotalLimit');
- return lib.doCheckLimit(uploadFileSize, maxFileSize, totalLimit);
- };
- /**
- * Checks if Uploader can respond to the HTTP request.
- */
- lib.canRespond = () => {
- // Check whether to use internal redirect of nginx or Apache.
- return lib.configManager.getConfig('crowi', 'fileUpload:local:useInternalRedirect');
- };
- /**
- * Respond to the HTTP request.
- * @param {Response} res
- * @param {Response} attachment
- */
- lib.respond = (res, attachment) => {
- // Responce using internal redirect of nginx or Apache.
- const storagePath = getFilePathOnStorage(attachment);
- const relativePath = path.relative(crowi.publicDir, storagePath);
- const internalPathRoot = lib.configManager.getConfig('crowi', 'fileUpload:local:internalRedirectPath');
- const internalPath = urljoin(internalPathRoot, relativePath);
- res.set('X-Accel-Redirect', internalPath);
- res.set('X-Sendfile', storagePath);
- return res.end();
- };
- return lib;
- };
|