123 lines
4.8 KiB
JavaScript
123 lines
4.8 KiB
JavaScript
const http = require("http");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const formidable = require("formidable");
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
const DATA = path.join(__dirname, "data.json");
|
|
const UPLOADS = path.join(__dirname, "uploads");
|
|
|
|
if (!fs.existsSync(UPLOADS)) fs.mkdirSync(UPLOADS);
|
|
|
|
function readData() {
|
|
try { return JSON.parse(fs.readFileSync(DATA, "utf8")); }
|
|
catch { return { items: [], log: [] }; }
|
|
}
|
|
function writeData(d) {
|
|
fs.writeFileSync(DATA, JSON.stringify(d, null, 2));
|
|
}
|
|
function body(req) {
|
|
return new Promise((resolve) => {
|
|
let s = "";
|
|
req.on("data", (c) => (s += c));
|
|
req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } });
|
|
});
|
|
}
|
|
|
|
http.createServer(async (req, res) => {
|
|
const url = req.url.split("?")[0];
|
|
|
|
if (req.method === "GET" && url === "/api/items") {
|
|
const d = readData();
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
return res.end(JSON.stringify(d.items));
|
|
}
|
|
|
|
if (req.method === "POST" && url === "/api/items") {
|
|
const item = await body(req);
|
|
const d = readData();
|
|
item.id = Date.now();
|
|
item.date = item.date || new Date().toISOString().slice(0, 10);
|
|
d.items.push(item);
|
|
d.log.push({ when: new Date().toISOString(), what: "добавлена запись: " + (item.fio || "") });
|
|
writeData(d);
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
return res.end(JSON.stringify({ ok: true }));
|
|
}
|
|
|
|
if (req.method === "DELETE" && url.startsWith("/api/items/")) {
|
|
const id = parseInt(url.split("/").pop());
|
|
const d = readData();
|
|
const idx = d.items.findIndex((i) => i.id === id);
|
|
if (idx !== -1) {
|
|
const removed = d.items.splice(idx, 1)[0];
|
|
d.log.push({ when: new Date().toISOString(), what: "удалена запись: " + (removed.fio || "") });
|
|
writeData(d);
|
|
}
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
return res.end(JSON.stringify({ ok: true }));
|
|
}
|
|
|
|
if (req.method === "PUT" && url.startsWith("/api/items/")) {
|
|
const id = parseInt(url.split("/").pop());
|
|
const upd = await body(req);
|
|
const d = readData();
|
|
const idx = d.items.findIndex((i) => i.id === id);
|
|
if (idx !== -1) {
|
|
d.items[idx] = { ...d.items[idx], ...upd, id };
|
|
d.log.push({ when: new Date().toISOString(), what: "изменена запись: " + (upd.fio || "") });
|
|
writeData(d);
|
|
}
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
return res.end(JSON.stringify({ ok: true }));
|
|
}
|
|
|
|
if (req.method === "POST" && url === "/api/upload") {
|
|
const form = formidable({ uploadDir: UPLOADS, keepExtensions: true, maxFileSize: 10 * 1024 * 1024 });
|
|
form.parse(req, function(err, fields, files) {
|
|
var result = { ok: false };
|
|
if (!err) {
|
|
var uploaded = [];
|
|
if (files.file) {
|
|
var arr = Array.isArray(files.file) ? files.file : [files.file];
|
|
arr.forEach(function(f) {
|
|
if (f && f.filepath) {
|
|
var name = f.originalFilename || "file";
|
|
var newPath = path.join(UPLOADS, Date.now() + "_" + name);
|
|
fs.renameSync(f.filepath, newPath);
|
|
uploaded.push({ name: name, path: "/uploads/" + path.basename(newPath) });
|
|
}
|
|
});
|
|
}
|
|
result.ok = true;
|
|
result.files = uploaded;
|
|
}
|
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
return res.end(JSON.stringify(result));
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (req.method === "GET" && url.startsWith("/uploads/")) {
|
|
var fName = path.basename(url);
|
|
var fPath = path.join(UPLOADS, fName);
|
|
if (fs.existsSync(fPath) && fs.statSync(fPath).isFile()) {
|
|
var ext = path.extname(fPath);
|
|
var mime = { ".pdf": "application/pdf", ".doc": "application/msword", ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xls": "application/vnd.ms-excel", ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif" };
|
|
res.writeHead(200, { "Content-Type": mime[ext] || "application/octet-stream", "Content-Disposition": 'inline; filename="' + fName + '"' });
|
|
return res.end(fs.readFileSync(fPath));
|
|
}
|
|
}
|
|
|
|
let file = url === "/" ? "/index.html" : url;
|
|
const full = path.join(__dirname, file);
|
|
if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) {
|
|
const ext = path.extname(full);
|
|
const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html";
|
|
res.writeHead(200, { "Content-Type": type + "; charset=utf-8" });
|
|
return res.end(fs.readFileSync(full));
|
|
}
|
|
|
|
res.writeHead(404); res.end("Not found");
|
|
}).listen(PORT, () => console.log("Сервер на порту " + PORT));
|