mirror of
				https://github.com/whyour/qinglong.git
				synced 2025-11-04 20:06:08 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			225 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { getFileContentByName, getLastModifyFilePath } from '../config/util';
 | 
						|
import { Router, Request, Response, NextFunction } from 'express';
 | 
						|
import { Container } from 'typedi';
 | 
						|
import { Logger } from 'winston';
 | 
						|
import config from '../config';
 | 
						|
import * as fs from 'fs';
 | 
						|
import { celebrate, Joi } from 'celebrate';
 | 
						|
const route = Router();
 | 
						|
 | 
						|
export default (app: Router) => {
 | 
						|
  app.use('/', route);
 | 
						|
 | 
						|
  route.get(
 | 
						|
    '/scripts/files',
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        const fileList = fs.readdirSync(config.scriptPath, 'utf-8');
 | 
						|
        res.send({
 | 
						|
          code: 200,
 | 
						|
          data: fileList
 | 
						|
            .map((x) => {
 | 
						|
              if (fs.lstatSync(config.scriptPath + x).isDirectory()) {
 | 
						|
                const childFileList = fs.readdirSync(
 | 
						|
                  config.scriptPath + x,
 | 
						|
                  'utf-8',
 | 
						|
                );
 | 
						|
                const dirStat = fs.statSync(`${config.scriptPath}${x}`);
 | 
						|
                return {
 | 
						|
                  title: x,
 | 
						|
                  value: x,
 | 
						|
                  key: x,
 | 
						|
                  mtime: dirStat.mtimeMs,
 | 
						|
                  disabled: true,
 | 
						|
                  children: childFileList
 | 
						|
                    .filter(
 | 
						|
                      (y) =>
 | 
						|
                        !fs
 | 
						|
                          .lstatSync(`${config.scriptPath}${x}/${y}`)
 | 
						|
                          .isDirectory(),
 | 
						|
                    )
 | 
						|
                    .map((y) => {
 | 
						|
                      const statObj = fs.statSync(
 | 
						|
                        `${config.scriptPath}${x}/${y}`,
 | 
						|
                      );
 | 
						|
                      return {
 | 
						|
                        title: y,
 | 
						|
                        value: y,
 | 
						|
                        key: y,
 | 
						|
                        mtime: statObj.mtimeMs,
 | 
						|
                        parent: x,
 | 
						|
                      };
 | 
						|
                    })
 | 
						|
                    .sort((a, b) => b.mtime - a.mtime),
 | 
						|
                };
 | 
						|
              } else {
 | 
						|
                const statObj = fs.statSync(config.scriptPath + x);
 | 
						|
                return { title: x, value: x, key: x, mtime: statObj.mtimeMs };
 | 
						|
              }
 | 
						|
            })
 | 
						|
            .sort((a, b) => b.mtime - a.mtime),
 | 
						|
        });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
 | 
						|
  route.get(
 | 
						|
    '/scripts/:file',
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        const path = req.query.path ? `${req.query.path}/` : '';
 | 
						|
        const content = getFileContentByName(
 | 
						|
          `${config.scriptPath}${path}${req.params.file}`,
 | 
						|
        );
 | 
						|
        res.send({ code: 200, data: content });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
 | 
						|
  route.post(
 | 
						|
    '/scripts',
 | 
						|
    celebrate({
 | 
						|
      body: Joi.object({
 | 
						|
        filename: Joi.string().required(),
 | 
						|
        path: Joi.string().allow(''),
 | 
						|
        content: Joi.string().allow(''),
 | 
						|
        originFilename: Joi.string().allow(''),
 | 
						|
      }),
 | 
						|
    }),
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        let { filename, path, content, originFilename } = req.body as {
 | 
						|
          filename: string;
 | 
						|
          path: string;
 | 
						|
          content: string;
 | 
						|
          originFilename: string;
 | 
						|
        };
 | 
						|
        if (!path) {
 | 
						|
          path = config.scriptPath;
 | 
						|
        }
 | 
						|
        if (!path.endsWith('/')) {
 | 
						|
          path += '/';
 | 
						|
        }
 | 
						|
        if (config.writePathList.every((x) => !path.startsWith(x))) {
 | 
						|
          return res.send({
 | 
						|
            code: 430,
 | 
						|
            data: '文件路径禁止访问',
 | 
						|
          });
 | 
						|
        }
 | 
						|
        if (!originFilename) {
 | 
						|
          originFilename = filename;
 | 
						|
        }
 | 
						|
        const originFilePath = `${path}${originFilename.replace(/\//g, '')}`;
 | 
						|
        const filePath = `${path}${filename.replace(/\//g, '')}`;
 | 
						|
        if (fs.existsSync(originFilePath)) {
 | 
						|
          if (!fs.existsSync(config.bakPath)) {
 | 
						|
            fs.mkdirSync(config.bakPath);
 | 
						|
          }
 | 
						|
          fs.copyFileSync(
 | 
						|
            originFilePath,
 | 
						|
            `${config.bakPath}${originFilename.replace(/\//g, '')}`,
 | 
						|
          );
 | 
						|
          if (filename !== originFilename) {
 | 
						|
            fs.unlinkSync(originFilePath);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        fs.writeFileSync(filePath, content);
 | 
						|
        return res.send({ code: 200 });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
 | 
						|
  route.put(
 | 
						|
    '/scripts',
 | 
						|
    celebrate({
 | 
						|
      body: Joi.object({
 | 
						|
        filename: Joi.string().required(),
 | 
						|
        path: Joi.string().allow(''),
 | 
						|
        content: Joi.string().required(),
 | 
						|
      }),
 | 
						|
    }),
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        let { filename, content, path } = req.body as {
 | 
						|
          filename: string;
 | 
						|
          content: string;
 | 
						|
          path: string;
 | 
						|
        };
 | 
						|
        const filePath = `${config.scriptPath}${path}/${filename}`;
 | 
						|
        fs.writeFileSync(filePath, content);
 | 
						|
        return res.send({ code: 200 });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
 | 
						|
  route.delete(
 | 
						|
    '/scripts',
 | 
						|
    celebrate({
 | 
						|
      body: Joi.object({
 | 
						|
        filename: Joi.string().required(),
 | 
						|
      }),
 | 
						|
    }),
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        let { filename } = req.body as {
 | 
						|
          filename: string;
 | 
						|
        };
 | 
						|
        const filePath = `${config.scriptPath}${filename}`;
 | 
						|
        fs.unlinkSync(filePath);
 | 
						|
        res.send({ code: 200 });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
 | 
						|
  route.post(
 | 
						|
    '/scripts/download',
 | 
						|
    celebrate({
 | 
						|
      body: Joi.object({
 | 
						|
        filename: Joi.string().required(),
 | 
						|
      }),
 | 
						|
    }),
 | 
						|
    async (req: Request, res: Response, next: NextFunction) => {
 | 
						|
      const logger: Logger = Container.get('logger');
 | 
						|
      try {
 | 
						|
        let { filename } = req.body as {
 | 
						|
          filename: string;
 | 
						|
        };
 | 
						|
        const filePath = `${config.scriptPath}${filename}`;
 | 
						|
        // const stats = fs.statSync(filePath);
 | 
						|
        // res.set({
 | 
						|
        //   'Content-Type': 'application/octet-stream', //告诉浏览器这是一个二进制文件
 | 
						|
        //   'Content-Disposition': 'attachment; filename=' + filename, //告诉浏览器这是一个需要下载的文件
 | 
						|
        //   'Content-Length': stats.size  //文件大小
 | 
						|
        // });
 | 
						|
        // fs.createReadStream(filePath).pipe(res);
 | 
						|
        return res.download(filePath, filename, (err) => {
 | 
						|
          return next(err);
 | 
						|
        });
 | 
						|
      } catch (e) {
 | 
						|
        logger.error('🔥 error: %o', e);
 | 
						|
        return next(e);
 | 
						|
      }
 | 
						|
    },
 | 
						|
  );
 | 
						|
};
 |