Files
owof-announcements/src/server/main.ts
T

82 lines
2.0 KiB
TypeScript

import { unlink } from "node:fs/promises";
import path from "node:path";
import express from "express";
import multer from "multer";
import ViteExpress from "vite-express";
import z from "zod";
import { db } from "./db/database.js";
const baseUploadsFolder = "uploads/";
const upload = multer({
dest: baseUploadsFolder,
});
const app = express();
const AddInput = z.object({
file: z.object({ filename: z.string() }),
body: z.object({
publication_date: z.coerce
.date()
.transform((x) => new Date(x).toISOString()),
title: z.string().nonempty(),
text: z.string().nonempty(),
}),
});
const DeleteInput = z.object({
announcementId: z.coerce.number().positive(),
});
app.get("/hello", (_, res) => {
res.send("Hello Vite + React + TypeScript!");
});
app.post("/api/announcements", upload.single("image"), async (req, res) => {
const addInput = AddInput.parse(req);
await db
.insertInto("announcements")
.values({
title: addInput.body.title,
text: addInput.body.text,
publication_date: addInput.body.publication_date,
image: addInput.file.filename,
})
.execute();
res.redirect("/");
});
app.get("/api/announcements", async (_, res) => {
// await new Promise((resolve) => setTimeout(resolve, 1000));
const announcements = await db
.selectFrom("announcements")
.select(["id", "title", "text", "publication_date", "image"])
.orderBy("announcements.publication_date", "desc")
.execute();
res.json(announcements);
});
app.delete("/api/announcements/:announcementId", async (req, res) => {
const { announcementId } = DeleteInput.parse(req.params);
const { image } = await db
.selectFrom("announcements")
.select("image")
.where("id", "=", announcementId)
.executeTakeFirstOrThrow();
await db
.deleteFrom("announcements")
.where("id", "=", announcementId)
.execute();
await unlink(path.join(baseUploadsFolder, image));
res.status(204).send();
});
ViteExpress.listen(app, 3000, () =>
console.log("Server is listening on port 3000..."),
);