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 @@
-
-
-
-
- Адресная книга подключений
-
-
-
-
-
-
-
- Адресная книга подключений
-
-
-
-
Управление папками
-
-
-
-
-
-
-
-
-
-
Добавить подключение
-
-
-
-
-
-
-
- | ID |
- Connection 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
+
+
+
+
+
+
+
+
Папки
+
+
+
+
+
+
+
+
\ No newline at end of file