From 642a022ef6a42153118b913cba73d241875c5d27 Mon Sep 17 00:00:00 2001 From: host Date: Sat, 25 Jul 2026 03:53:57 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api.js | 73 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/frontend/src/api.js b/frontend/src/api.js index 1ae6121..873b7a0 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -1,5 +1,74 @@ -getInstanceLive: (id) => request(`/instances/${id}/live`), +const BASE = "/api"; + +function getToken() { + return localStorage.getItem("token"); +} + +async function request(path, { method = "GET", body, auth = true } = {}) { + const headers = {}; + let payload = body; + + if (body instanceof URLSearchParams) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + } else if (body !== undefined) { + headers["Content-Type"] = "application/json"; + payload = JSON.stringify(body); + } + + if (auth) { + const token = getToken(); + if (token) headers["Authorization"] = `Bearer ${token}`; + } + + const res = await fetch(`${BASE}${path}`, { method, headers, body: payload }); + + if (!res.ok) { + let detail = res.statusText; + try { + const data = await res.json(); + detail = data.detail || detail; + } catch { + /* тело не JSON */ + } + throw new Error(typeof detail === "string" ? detail : JSON.stringify(detail)); + } + + if (res.status === 204) return null; + return res.json(); +} + +export const api = { + register: (email, password) => + request("/auth/register", { method: "POST", body: { email, password }, auth: false }), + + login: async (email, password) => { + const form = new URLSearchParams(); + form.set("username", email); + form.set("password", password); + const data = await request("/auth/login", { method: "POST", body: form, auth: false }); + localStorage.setItem("token", data.access_token); + return data; + }, + + logout: () => localStorage.removeItem("token"), + + me: () => request("/auth/me"), + + listTemplates: () => request("/templates"), + createTemplate: (payload) => request("/templates", { method: "POST", body: payload }), + + listInstances: () => request("/instances"), + createInstance: (payload) => request("/instances", { method: "POST", body: payload }), + getInstance: (id) => request(`/instances/${id}`), + getInstanceStatus: (id) => request(`/instances/${id}/status`), + instanceAction: (id, action) => + request(`/instances/${id}/action`, { method: "POST", body: { action } }), + getInstanceLive: (id) => request(`/instances/${id}/live`), getInstanceIp: (id) => request(`/instances/${id}/ip`), deleteInstance: (id) => request(`/instances/${id}`, { method: "DELETE" }), - fetchProxmoxTemplates: () => request("/templates/from-proxmox"), \ No newline at end of file + fetchProxmoxTemplates: () => request("/templates/from-proxmox"), + deleteTemplate: (id) => request(`/templates/${id}`, { method: "DELETE" }), + listUsers: () => request("/admin/users"), + toggleUser: (id) => request(`/admin/users/${id}/toggle-active`, { method: "POST" }), +}; \ No newline at end of file