diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/index.ts | 17 | ||||
| -rw-r--r-- | app/logger.ts | 23 | ||||
| -rw-r--r-- | app/middlewares/multer.ts | 21 | ||||
| -rw-r--r-- | app/routes/upload.ts | 74 |
4 files changed, 135 insertions, 0 deletions
diff --git a/app/index.ts b/app/index.ts new file mode 100644 index 0000000..8921076 --- /dev/null +++ b/app/index.ts @@ -0,0 +1,17 @@ +import { logger } from './logger.js'; +import express from 'express'; +import upload from './routes/upload.js'; +import config from 'config'; + +const startDate = new Date(); + +logger.info(`Welcome to scrapbook, ${startDate.toString()}`); +logger.info(''); + +const app = express(); + +app.use(upload); + +app.listen(config.get('port'), () => { + logger.info(`Server started on port ${config.get('port')}`); +}); diff --git a/app/logger.ts b/app/logger.ts new file mode 100644 index 0000000..4ce0150 --- /dev/null +++ b/app/logger.ts @@ -0,0 +1,23 @@ +import winston from 'winston'; + +const enumerateErrorFormat = winston.format((info) => { + if (info instanceof Error) { + Object.assign(info, { message: info.stack }); + } + return info; + }); + +export const logger = winston.createLogger({ + level: process.env.LOGGING_LEVEL === 'development' ? 'debug' : 'info', + format: winston.format.combine( + enumerateErrorFormat(), + winston.format.colorize(), + winston.format.splat(), + winston.format.printf(({ level, message }) => `${level}: ${message}`) + ), + transports: [ + new winston.transports.Console({ + stderrLevels: ['error'], + }), + ], +}); diff --git a/app/middlewares/multer.ts b/app/middlewares/multer.ts new file mode 100644 index 0000000..f35ca08 --- /dev/null +++ b/app/middlewares/multer.ts @@ -0,0 +1,21 @@ +import multer from 'multer'; + +const storage = multer.diskStorage({ + destination: '/tmp/www-uploads', + filename: function (req, file, cb) { + const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9) + cb(null, file.fieldname + '-' + uniqueSuffix) + } +}); +export const upload = multer({ + storage: storage, + limits: { + fileSize: 1024 * 1024 * 500 + }, + fileFilter: function (req, file, cb) { + if (!file.originalname.match(/\.(zip)$/)) { + return cb(new Error('Only accepting zip files')); + } + cb(null, true); + } +}); diff --git a/app/routes/upload.ts b/app/routes/upload.ts new file mode 100644 index 0000000..fb98411 --- /dev/null +++ b/app/routes/upload.ts @@ -0,0 +1,74 @@ +import express from 'express'; +import { logger } from '../logger.js'; +import { upload } from '../middlewares/multer.js'; +import config from 'config'; +import AdmZip from 'adm-zip'; +import fs from 'fs-extra'; + +const router = express.Router(); + +router.use('/:page/upload', upload.single('content')); + +router.post('/:page/upload', async (req, res) => { + if (!req.file) { + res.status(400).send('Bad request'); + return; + } + + const site = config.get('sites')[req.params.page]; + if (!site) { + res.status(404).send('Not found'); + return; + } + + logger.info(`Received upload for '${req.params.page}'`); + const decompressed = `/tmp/www-uploads/${req.file.filename}-decompressed`; + + let admZip: AdmZip; + try { + admZip = new AdmZip(req.file.path); + } catch (e) { + logger.error(`Error creating zip file: ${e}`); + res.status(500).send('Internal server error'); + return; + } + + logger.info(`Decompressing file to ${decompressed}`); + try { + admZip.extractAllTo(decompressed); + } catch (e) { + logger.error(`Error decompressing file: ${e}`); + res.status(500).send('Internal server error'); + return; + } + + logger.info(`Moving decompressed files to ${site.path}`); + try { + fs.emptyDirSync(site.path); + fs.readdirSync(decompressed).forEach(file => { + fs.moveSync(`${decompressed}/${file}`, `${site.path}/${file}`); + }); + } catch (e) { + logger.error(`Error moving files: ${e}`); + res.status(500).send('Internal server error'); + return; + } + + logger.info(`Deleting temporary files`); + try { + fs.removeSync(decompressed); + fs.removeSync(req.file.path); + } catch (e) { + logger.error(`Error deleting temporary files: ${e}`); + res.status(500).send('Internal server error'); + return; + } + + const endDate = new Date(); + logger.info(`Upload complete. New site published at ${endDate.toString()}.`); + logger.info(''); + + res.status(200).send('OK'); +}); + +export default router; |
