aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/index.ts17
-rw-r--r--app/logger.ts23
-rw-r--r--app/middlewares/multer.ts21
-rw-r--r--app/routes/upload.ts74
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;