diff --git a/123 b/123 new file mode 100644 index 0000000..871cae9 --- /dev/null +++ b/123 @@ -0,0 +1 @@ +323 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0291ae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app.py . +COPY templates/ ./templates/ +EXPOSE 8001 +CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8001"] \ No newline at end of file diff --git a/README.md b/README.md index eed5903..ce73df1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,2 @@ # addressbook_web -test \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..6c40d9b --- /dev/null +++ b/app.py @@ -0,0 +1,137 @@ +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +import sqlite3 +import datetime +from fastapi.staticfiles import StaticFiles +from fastapi.responses import FileResponse + +app = FastAPI() + +# Соединение с базой данных +conn = sqlite3.connect("/db/rustdesk.db", check_same_thread=False) +cursor = conn.cursor() + +# Создаем таблицы +cursor.execute(""" +CREATE TABLE IF NOT EXISTS folders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + parent_id INTEGER, + FOREIGN KEY (parent_id) REFERENCES folders(id) +) +""") +cursor.execute(""" +CREATE TABLE IF NOT EXISTS installs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + rust_id TEXT, + computer_name TEXT, + install_time TEXT, + folder_id INTEGER, + FOREIGN KEY (folder_id) REFERENCES folders(id) +) +""") +conn.commit() + +# Модели данных +class Folder(BaseModel): + name: str + parent_id: int | None = None + +class FolderUpdate(BaseModel): + name: str + +class InstallData(BaseModel): + rust_id: str + computer_name: str + install_time: str | None = None + folder_id: int | None = None + +# Монтируем папку templates как статические файлы +app.mount("/templates", StaticFiles(directory="templates"), name="templates") + +# Главная страница +@app.get("/") +async def root(): + return FileResponse("templates/index.html") + +# --- Folders API --- +@app.get("/api/folders") +def get_folders(): + cursor.execute("SELECT * FROM folders") + rows = cursor.fetchall() + return [{"id": row[0], "name": row[1], "parent_id": row[2]} for row in rows] + +@app.post("/api/folders") +def add_folder(folder: Folder): + cursor.execute("INSERT INTO folders (name, parent_id) VALUES (?, ?)", + (folder.name, folder.parent_id)) + conn.commit() + return {"status": "success", "id": cursor.lastrowid} + +@app.put("/api/folders/{folder_id}") +def update_folder(folder_id: int, folder: FolderUpdate): + cursor.execute("UPDATE folders SET name = ? WHERE id = ?", (folder.name, folder_id)) + conn.commit() + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail="Папка не найдена") + return {"status": "success"} + +@app.delete("/api/folders/{folder_id}") +def delete_folder(folder_id: int): + cursor.execute("DELETE FROM folders WHERE id = ?", (folder_id,)) + conn.commit() + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail="Папка не найдена") + return {"status": "success"} + +# --- Installs API --- +@app.get("/api/installs") +def get_installs(): + cursor.execute(""" + SELECT i.id, i.rust_id, i.computer_name, i.install_time, i.folder_id, f.name as folder_name + FROM installs i + LEFT JOIN folders f ON i.folder_id = f.id + """) + rows = cursor.fetchall() + return [{"id": row[0], "rust_id": row[1], "computer_name": row[2], + "install_time": row[3], "folder_id": row[4], "folder_name": row[5]} + for row in rows] + +@app.post("/api/install") +def add_install(data: InstallData): + install_time = data.install_time or datetime.datetime.now().isoformat() + cursor.execute("INSERT INTO installs (rust_id, computer_name, install_time, folder_id) VALUES (?, ?, ?, ?)", + (data.rust_id, data.computer_name, install_time, data.folder_id)) + conn.commit() + return {"status": "success"} + +@app.put("/api/install/{install_id}") +def update_install(install_id: int, data: InstallData): + cursor.execute(""" + UPDATE installs + SET rust_id = ?, computer_name = ?, install_time = ?, folder_id = ? + WHERE id = ? + """, (data.rust_id, data.computer_name, data.install_time or datetime.datetime.now().isoformat(), + data.folder_id, install_id)) + conn.commit() + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail="Запись не найдена") + return {"status": "success"} + +@app.delete("/api/install/{install_id}") +def delete_install(install_id: int): + cursor.execute("DELETE FROM installs WHERE id = ?", (install_id,)) + conn.commit() + if cursor.rowcount == 0: + raise HTTPException(status_code=404, detail="Запись не найдена") + return {"status": "success"} + +# CORS +from fastapi.middleware.cors import CORSMiddleware +app.add_middleware( + CORSMiddleware, + allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 0fb611d..6314e60 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,23 +1,9 @@ version: '3.8' - services: - backend: - build: - context: ./backend - dockerfile: Dockerfile + rustdesk-organizer: + build: . ports: - - "8001:8001" # Порт для FastAPI + - "8001:8001" volumes: - - ./db:/db # Монтирование базы данных - - frontend: - image: nginx:latest - ports: - - "8081:80" # Порт для фронтенда - volumes: - - ./frontend:/usr/share/nginx/html # Монтирование фронтенда - - db: - image: sqlite3:latest # Или используй существующий volume с rustdesk.db - volumes: - - ./db:/db \ No newline at end of file + - ./db:/db + restart: unless-stopped \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 664f588..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - Адресная книга подключений - - - - - - - -

Адресная книга подключений

- - -
-

Управление папками

- - - - - -
- - -
-

Добавить подключение

-
- - - - - -
-
- - - - - - - - - - - - - - -
IDConnection IDИмяТипПапкаДействие
- - \ No newline at end of file diff --git a/frontend/script.js b/frontend/script.js deleted file mode 100644 index 4ac12d8..0000000 --- a/frontend/script.js +++ /dev/null @@ -1,239 +0,0 @@ -const API_URL = "http://localhost:8001/api"; - -$(document).ready(function () { - loadFolders(); - loadConnections(); - - // Загрузка папок - function loadFolders() { - $.getJSON(`${API_URL}/folders`, function (folders) { - $('#parentFolder, #connectionFolder').empty(); - $('#parentFolder, #connectionFolder').append(''); - folders.forEach(folder => { - $('#parentFolder, #connectionFolder').append( - `` - ); - }); - }); - } - - // Загрузка подключений в таблицу - function loadConnections() { - $.getJSON(`${API_URL}/connections`, function (data) { - let table = $('#connectionsTable').DataTable({ - "destroy": true, - "data": data, - "columns": [ - { "data": "id" }, - { - "data": "connection_id", - "render": function (data, type, row) { - if (row.type === "RustDesk") { - return `${data}`; - } - return data; - } - }, - { "data": "name" }, - { "data": "type" }, - { - "data": "folder_id", - "render": function (data, type, row) { - return data ? getFolderName(data) : "Без папки"; - } - }, - { - "data": "id", - "render": function (data) { - return ` - - - - `; - } - } - ] - }); - }); - } - - // Получение имени папки по ID - function getFolderName(folderId) { - let folderName = "Без папки"; - $.ajax({ - url: `${API_URL}/folders/${folderId}`, - async: false, - success: function (folder) { - folderName = folder.name; - } - }); - return folderName; - } - - // Создание папки - window.createFolder = function () { - let name = $('#folderName').val(); - let parentId = $('#parentFolder').val() || null; - $.ajax({ - url: `${API_URL}/folders`, - type: 'POST', - contentType: 'application/json', - data: JSON.stringify({ name, parent_id: parentId }), - success: function () { - alert("Папка создана!"); - loadFolders(); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - }; - - // Редактирование папки (пример, нужно уточнить UI) - window.editFolder = function () { - let folderId = prompt("Введите ID папки для редактирования:"); - if (folderId) { - let name = prompt("Новое имя папки:"); - let parentId = prompt("ID родительской папки (оставьте пустым для корневой):") || null; - $.ajax({ - url: `${API_URL}/folders/${folderId}`, - type: 'PUT', - contentType: 'application/json', - data: JSON.stringify({ name, parent_id: parentId }), - success: function () { - alert("Папка обновлена!"); - loadFolders(); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - } - }; - - // Удаление папки - window.deleteFolder = function () { - let folderId = prompt("Введите ID папки для удаления:"); - if (folderId && confirm("Вы уверены?")) { - $.ajax({ - url: `${API_URL}/folders/${folderId}`, - type: 'DELETE', - success: function () { - alert("Папка удалена!"); - loadFolders(); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - } - }; - - // Добавление подключения - $('#addConnectionForm').submit(function (event) { - event.preventDefault(); - let connectionId = $('#connectionId').val(); - let name = $('#connectionName').val(); - let type = $('#connectionType').val(); - let folderId = $('#connectionFolder').val() || null; - - $.ajax({ - url: `${API_URL}/connections`, - type: 'POST', - contentType: 'application/json', - data: JSON.stringify({ connection_id: connectionId, name, type, folder_id: folderId }), - success: function () { - alert("Подключение добавлено!"); - loadConnections(); - $('#addConnectionForm')[0].reset(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - }); - - // Редактирование подключения - window.editConnection = function (id) { - let connection = promptConnectionDetails(id); - if (connection) { - $.ajax({ - url: `${API_URL}/connections/${id}`, - type: 'PUT', - contentType: 'application/json', - data: JSON.stringify(connection), - success: function () { - alert("Подключение обновлено!"); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - } - }; - - // Удаление подключения - window.deleteConnection = function (id) { - if (confirm("Вы уверены, что хотите удалить подключение?")) { - $.ajax({ - url: `${API_URL}/connections/${id}`, - type: 'DELETE', - success: function () { - alert("Подключение удалено!"); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - } - }; - - // Перемещение подключения - window.moveConnection = function (id) { - let folderId = prompt("Введите ID папки для перемещения (оставьте пустым для корневой):") || null; - $.ajax({ - url: `${API_URL}/connections/${id}`, - type: 'PUT', - contentType: 'application/json', - data: JSON.stringify({ folder_id: folderId }), - success: function () { - alert("Подключение перемещено!"); - loadConnections(); - }, - error: function (xhr) { - alert("Ошибка: " + xhr.responseJSON.detail); - } - }); - }; - - // Функция для запроса деталей подключения через prompt (можно улучшить с модальным окном) - function promptConnectionDetails(id) { - let connectionId = prompt("Новый ID подключения:"); - let name = prompt("Новое имя подключения:"); - let type = prompt("Новый тип подключения (RustDesk, SSH, RDP):"); - let folderId = prompt("ID папки (оставьте пустым для корневой):") || null; - if (connectionId && name && type) { - return { connection_id: connectionId, name, type, folder_id: folderId }; - } - return null; - } - - // Обработка клика по RustDesk ссылке - window.openRustDesk = function(rustId) { - if (confirm("Подключиться к устройству с ID " + rustId + "?")) { - if (typeof navigator.msLaunchUri !== 'undefined') { - navigator.msLaunchUri(`rustdesk://${rustId}`, - function() { console.log("Успешно запущен RustDesk"); }, - function() { alert("Не удалось запустить RustDesk. Убедитесь, что RustDesk установлен и зарегистрирован для обработки rustdesk://."); } - ); - } else { - window.location.href = `rustdesk://${rustId}`; - } - } - }; -}); \ No newline at end of file diff --git a/frontend/style.css b/frontend/style.css deleted file mode 100644 index afbcd9c..0000000 --- a/frontend/style.css +++ /dev/null @@ -1,15 +0,0 @@ -body { - font-family: Arial, sans-serif; - margin: 20px; -} - -.folder-controls, .connection-controls { - margin-bottom: 20px; - padding: 10px; - border: 1px solid #ccc; -} - -input, select, button { - margin: 5px; - padding: 5px; -} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f0615cf --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +fastapi +uvicorn \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..0b92a3a --- /dev/null +++ b/templates/index.html @@ -0,0 +1,215 @@ + + + + + Органайзер RustDesk + + + + + + +
+

Папки

+
+ +
+
+

Органайзер RustDesk

+
+

Добавить запись

+ + + + +
+
+
+ + + + \ No newline at end of file