Eventer/src/server.ts

135 lines
3.3 KiB
TypeScript

import express from "express";
import multer, { FileFilterCallback } from "multer";
import sizeOf from "image-size";
import * as fsp from "fs/promises";
import * as path from "path";
const app = express();
const publicDirname = path.join(__dirname, "../public");
const uploadDirname = path.join(__dirname, "../uploads");
const MAX_FILE_SIZE_IN_BYTES = 15 * 1_000_000; // 15 mb
const DEVELOPMENT_PORT = 8000;
const IMAGE_SQUARE_VALIDATION_TOLERENCE = 0.2;
import allowedUsers from "./allowedUsers.json";
import * as fs from "fs";
import * as dotenv from "dotenv";
import { makePullRequest } from "./giteaClient";
import { validateForm } from "./handleForm";
dotenv.config();
const devQuestId = "cdalek";
const validateAuthorization = (req, res, next) => {
// TODO: Replace with actual quest id from request
if (!allowedUsers.includes(devQuestId)) {
res.status(401);
res.sendFile(path.join(publicDirname, "unauthorized.html"));
} else {
return next();
}
};
// Validate user's quest id
app.use(validateAuthorization);
// Configure multer for file uploads
const storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, uploadDirname);
},
filename: function (req, file, callback) {
callback(null, Date.now() + "--" + file.originalname);
},
});
const fileFilter = async (
_,
file: Express.Multer.File,
callback: FileFilterCallback
) => {
let mimeType = file.mimetype.toLowerCase();
if (
!mimeType.includes("jpeg") &&
!mimeType.includes("png") &&
!mimeType.includes("jpg")
) {
callback(
Error("Invalid file type! Only JPEG and PNG files are supported!")
);
} else {
callback(null, true);
}
};
const validateImageIsSquare = async(
file: Express.Multer.File
) => {
const dimensions = sizeOf(file.path);
const ratio = dimensions.height / dimensions.width;
return ratio < 1 + IMAGE_SQUARE_VALIDATION_TOLERENCE && ratio > 1 - IMAGE_SQUARE_VALIDATION_TOLERENCE;
}
let upload = multer({
storage: storage,
fileFilter: fileFilter,
limits: { fileSize: MAX_FILE_SIZE_IN_BYTES },
});
// Routes
app.get("/", async (req, res) => {
res.sendFile(path.join(publicDirname, "index.html"));
// TODO: Implement this for www
// makePullRequest();
});
app.post("/event", upload.single("poster"), async (req, res) => {
const { name, short, long, start, end, register, location, online } =
req.body;
const validationStatus = validateForm(
name,
short,
long,
start,
end,
register,
location,
online
);
if(!(await validateImageIsSquare(req.file))) {
// Delete the file
await fsp.unlink(req.file.path);
return res.status(400).send("The poster photo must be approximately square.")
}
if (validationStatus === true) {
res.send(
"The event has been validated (change it to added after finished) successfully."
);
// Perform API request
} else {
res.status(400).send(validationStatus);
}
});
function initUploadDir() {
// Create upload directory if it doesn't exist already
if (!fs.existsSync(uploadDirname)) {
fs.mkdirSync(uploadDirname);
}
}
// Allows serving static files
app.use(express.static(publicDirname));
initUploadDir();
app.listen(DEVELOPMENT_PORT, () => {
console.log(`Listening on http://localhost:${DEVELOPMENT_PORT}`);
});