diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 0c2da19..0000000 --- a/package-lock.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "biot-zhambyl", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "biot-zhambyl" - } - } -} diff --git a/redirect.html b/redirect.html new file mode 100644 index 0000000..723666c --- /dev/null +++ b/redirect.html @@ -0,0 +1,11 @@ + + + + + + Перенаправление... + + +

Перенаправляем на сайт... Если не перенаправило, нажмите здесь

+ + diff --git a/server.js b/server.js index e0e2adc..1becba2 100644 --- a/server.js +++ b/server.js @@ -1,245 +1 @@ -const http = require("http"); -const fs = require("fs"); -const path = require("path"); - -const PORT = process.env.PORT || 3000; -const DATA = path.join(__dirname, "data.json"); -const USERS_FILE = path.join(__dirname, "users.json"); - -// Простая авторизация по токенам -function loadUsers() { - try { return JSON.parse(fs.readFileSync(USERS_FILE, "utf8")); } catch (_) { - return { users: [{ id: "admin", name: "Админ", token: "tok_" + Date.now() }] }; - } -} -function saveUsers(users) { - fs.writeFileSync(USERS_FILE, JSON.stringify(users, null, 2)); -} - -function readData() { - try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return { events: [] }; } -} -function writeData(data) { - fs.writeFileSync(DATA, JSON.stringify(data, 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({}); } }); - }); -} - -function checkAuth(req) { - const token = req.headers.authorization?.replace("Bearer ", ""); - if (!token) return null; - const users = loadUsers(); - return users.users.find(u => u.token === token) || null; -} - -http.createServer(async (req, res) => { - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); - - if (req.method === "OPTIONS") { - res.writeHead(200); - return res.end(); - } - - const urlPath = req.url.split("?")[0]; - const queryString = req.url.split("?")[1] || ""; - const query = new URLSearchParams(queryString); - - // API: Авторизация (GET и POST для работы через proxy) - if ((req.method === "POST" || req.method === "GET") && urlPath === "/service/login") { - const username = query.get("username") || (await body(req)).username; - const password = query.get("password") || (await body(req)).password; - const users = loadUsers(); - const user = users.users.find(u => u.id === username && u.password === password); - if (user) { - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true, token: user.token, name: user.name })); - } - res.writeHead(401, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Неверный логин или пароль" })); - } - - // API: Получить текущего пользователя - if (req.method === "GET" && urlPath === "/service/me") { - const user = checkAuth(req); - if (user) { - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ id: user.id, name: user.name, isAdmin: user.id === 'admin' })); - } - res.writeHead(401, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Не авторизован" })); - } - - // API: Получить всех пользователей (только admin) - if (req.method === "GET" && urlPath === "/service/users") { - const user = checkAuth(req); - if (!user || user.id !== 'admin') { - res.writeHead(403, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Только для администратора" })); - } - const users = loadUsers(); - // Не отдаём пароли и токены - const safeUsers = users.users.map(u => ({ id: u.id, name: u.name })); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify(safeUsers)); - } - - // API: Добавить пользователя (только admin) - if (req.method === "POST" && urlPath === "/service/users") { - const user = checkAuth(req); - if (!user || user.id !== 'admin') { - res.writeHead(403, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Только для администратора" })); - } - const { id, name, password } = await body(req); - if (!id || !name || !password) { - res.writeHead(400, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Нужны id, name и password" })); - } - const users = loadUsers(); - if (users.users.find(u => u.id === id)) { - res.writeHead(400, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Пользователь уже существует" })); - } - const token = "tok_" + id + "_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8); - users.users.push({ id, name, password, token }); - saveUsers(users); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true, user: { id, name, password, token } })); - } - - // API: Удалить пользователя (только admin, нельзя удалить admin и себя) - if (req.method === "DELETE" && urlPath.startsWith("/service/users/")) { - const user = checkAuth(req); - if (!user || user.id !== 'admin') { - res.writeHead(403, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Только для администратора" })); - } - const idToDelete = urlPath.split("/")[3]; - if (idToDelete === 'admin') { - res.writeHead(400, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Нельзя удалить admin" })); - } - const users = loadUsers(); - users.users = users.users.filter(u => u.id !== idToDelete); - saveUsers(users); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true })); - } - - // API: Изменить пароль пользователя (только admin) - if (req.method === "PUT" && urlPath.startsWith("/service/users/")) { - const user = checkAuth(req); - if (!user || user.id !== 'admin') { - res.writeHead(403, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Только для администратора" })); - } - const userId = urlPath.split("/")[3]; - const { password } = await body(req); - if (!password) { - res.writeHead(400, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Нужен password" })); - } - const users = loadUsers(); - const u = users.users.find(u => u.id === userId); - if (!u) { - res.writeHead(404, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Пользователь не найден" })); - } - u.password = password; - saveUsers(users); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true })); - } - - // API: GET /service/events - if (req.method === "GET" && urlPath === "/service/events") { - const tab = query.get("tab") || "biot"; - const data = readData(); - const events = data[tab + "Events"] || []; - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify(events)); - } - - // API: POST /service/events (требуется авторизация) - if (req.method === "POST" && urlPath === "/service/events") { - const user = checkAuth(req); - if (!user) { - res.writeHead(401, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Требуется авторизация" })); - } - const tab = query.get("tab") || "biot"; - console.log("POST /service/events tab:", tab, "user:", user.name); - const data = readData(); - const event = await body(req); - console.log("Event data:", event); - event.id = Date.now(); - event.tab = tab; - event.createdBy = user.id; - const arrayName = tab + "Events"; - if (!data[arrayName]) data[arrayName] = []; - data[arrayName].push(event); - console.log("Saving to:", arrayName, "Total:", data[arrayName].length); - writeData(data); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true, event })); - } - - // API: PUT /service/events/:id (требуется авторизация) - if (req.method === "PUT" && urlPath.startsWith("/service/events/")) { - const user = checkAuth(req); - if (!user) { - res.writeHead(401, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Требуется авторизация" })); - } - const tab = query.get("tab") || "biot"; - const id = parseInt(urlPath.split("/")[3]); - const data = readData(); - const events = data[tab + "Events"] || []; - const idx = events.findIndex(e => e.id === id); - if (idx !== -1) { - events[idx] = { ...events[idx], ...await body(req), updatedBy: user.id }; - data[tab + "Events"] = events; - writeData(data); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true })); - } - res.writeHead(404); - return res.end(JSON.stringify({ error: "Не найдено" })); - } - - // API: DELETE /service/events/:id (требуется авторизация) - if (req.method === "DELETE" && urlPath.startsWith("/service/events/")) { - const user = checkAuth(req); - if (!user) { - res.writeHead(401, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ error: "Требуется авторизация" })); - } - const tab = query.get("tab") || "biot"; - const id = parseInt(urlPath.split("/")[3]); - const data = readData(); - data[tab + "Events"] = (data[tab + "Events"] || []).filter(e => e.id !== id); - writeData(data); - res.writeHead(200, { "Content-Type": "application/json" }); - return res.end(JSON.stringify({ ok: true })); - } - - // Статика - let file = urlPath === "/" ? "/index.html" : urlPath; - 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)); +404: Not Found \ No newline at end of file