Add Notification and new mini desing
This commit is contained in:
153
backend/main.py
153
backend/main.py
@@ -73,8 +73,8 @@ IS_WINDOWS = sys.platform == 'win32'
|
||||
def init_users():
|
||||
if not USERS_FILE.exists():
|
||||
admin_user = {
|
||||
"username": "Sofa12345",
|
||||
"password": pwd_context.hash("arkonsad123"),
|
||||
"username": "Root",
|
||||
"password": pwd_context.hash("Admin"),
|
||||
"role": "admin",
|
||||
"servers": []
|
||||
}
|
||||
@@ -1005,23 +1005,88 @@ async def download_file(server_name: str, path: str, user: dict = Depends(get_cu
|
||||
|
||||
@app.post("/api/servers/{server_name}/files/upload")
|
||||
async def upload_file(server_name: str, path: str, file: UploadFile = File(...), user: dict = Depends(get_current_user)):
|
||||
print(f"Upload request: server={server_name}, path='{path}', filename='{file.filename}'")
|
||||
|
||||
if not check_server_access(user, server_name):
|
||||
raise HTTPException(403, "Нет доступа к этому серверу")
|
||||
|
||||
server_path = SERVERS_DIR / server_name
|
||||
target_path = server_path / path / file.filename
|
||||
|
||||
print(f"Target path: {target_path}")
|
||||
print(f"Server path: {server_path}")
|
||||
print(f"Path starts with server_path: {str(target_path).startswith(str(server_path))}")
|
||||
|
||||
if not str(target_path).startswith(str(server_path)):
|
||||
raise HTTPException(400, "Недопустимый путь")
|
||||
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
print(f"Created directory: {target_path.parent}")
|
||||
except Exception as e:
|
||||
print(f"Error creating directory: {e}")
|
||||
raise HTTPException(500, f"Ошибка создания директории: {str(e)}")
|
||||
|
||||
with open(target_path, "wb") as f:
|
||||
content = await file.read()
|
||||
f.write(content)
|
||||
try:
|
||||
with open(target_path, "wb") as f:
|
||||
content = await file.read()
|
||||
f.write(content)
|
||||
print(f"File written successfully: {target_path}")
|
||||
except Exception as e:
|
||||
print(f"Error writing file: {e}")
|
||||
raise HTTPException(500, f"Ошибка записи файла: {str(e)}")
|
||||
|
||||
return {"message": "Файл загружен"}
|
||||
|
||||
@app.post("/api/servers/{server_name}/files/create")
|
||||
async def create_file_or_folder(server_name: str, data: dict, user: dict = Depends(get_current_user)):
|
||||
"""Создать новый файл или папку"""
|
||||
if not check_server_access(user, server_name):
|
||||
raise HTTPException(403, "Нет доступа к этому серверу")
|
||||
|
||||
item_type = data.get("type") # "file" or "folder"
|
||||
name = data.get("name", "").strip()
|
||||
path = data.get("path", "") # Текущая папка
|
||||
|
||||
if not name:
|
||||
raise HTTPException(400, "Имя не может быть пустым")
|
||||
|
||||
if item_type not in ["file", "folder"]:
|
||||
raise HTTPException(400, "Тип должен быть 'file' или 'folder'")
|
||||
|
||||
server_path = SERVERS_DIR / server_name
|
||||
|
||||
# Формируем полный путь
|
||||
if path:
|
||||
full_path = server_path / path / name
|
||||
else:
|
||||
full_path = server_path / name
|
||||
|
||||
print(f"Creating {item_type}: {full_path}")
|
||||
|
||||
# Проверка безопасности
|
||||
if not str(full_path).startswith(str(server_path)):
|
||||
raise HTTPException(400, "Недопустимый путь")
|
||||
|
||||
try:
|
||||
if item_type == "folder":
|
||||
# Создаем папку
|
||||
full_path.mkdir(parents=True, exist_ok=True)
|
||||
# Создаем .gitkeep чтобы папка не была пустой
|
||||
gitkeep = full_path / ".gitkeep"
|
||||
gitkeep.touch()
|
||||
print(f"Folder created: {full_path}")
|
||||
else:
|
||||
# Создаем файл
|
||||
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
full_path.touch()
|
||||
print(f"File created: {full_path}")
|
||||
|
||||
return {"message": f"{'Папка' if item_type == 'folder' else 'Файл'} создан(а)", "path": str(full_path)}
|
||||
except Exception as e:
|
||||
print(f"Error creating {item_type}: {e}")
|
||||
raise HTTPException(500, f"Ошибка создания: {str(e)}")
|
||||
|
||||
@app.delete("/api/servers/{server_name}/files")
|
||||
async def delete_file(server_name: str, path: str, user: dict = Depends(get_current_user)):
|
||||
if not check_server_access(user, server_name):
|
||||
@@ -1098,6 +1163,82 @@ async def rename_file(server_name: str, old_path: str, new_name: str, user: dict
|
||||
old_file_path.rename(new_file_path)
|
||||
return {"message": "Файл переименован"}
|
||||
|
||||
@app.post("/api/servers/{server_name}/files/move")
|
||||
async def move_file(server_name: str, data: dict, user: dict = Depends(get_current_user)):
|
||||
"""Переместить файл или папку"""
|
||||
if not check_server_access(user, server_name):
|
||||
raise HTTPException(403, "Нет доступа к этому серверу")
|
||||
|
||||
source_path = data.get("source", "").strip()
|
||||
destination_path = data.get("destination", "").strip()
|
||||
|
||||
if not source_path:
|
||||
raise HTTPException(400, "Не указан исходный путь")
|
||||
|
||||
server_path = SERVERS_DIR / server_name
|
||||
source_full = server_path / source_path
|
||||
|
||||
# Формируем путь назначения
|
||||
if destination_path:
|
||||
# Извлекаем имя файла из source_path
|
||||
file_name = source_full.name
|
||||
dest_full = server_path / destination_path / file_name
|
||||
else:
|
||||
# Перемещение в корень
|
||||
file_name = source_full.name
|
||||
dest_full = server_path / file_name
|
||||
|
||||
print(f"Moving: {source_full} -> {dest_full}")
|
||||
|
||||
# Проверки безопасности
|
||||
if not source_full.exists():
|
||||
raise HTTPException(404, "Исходный файл не найден")
|
||||
|
||||
if not str(source_full).startswith(str(server_path)):
|
||||
raise HTTPException(400, "Недопустимый исходный путь")
|
||||
|
||||
if not str(dest_full).startswith(str(server_path)):
|
||||
raise HTTPException(400, "Недопустимый путь назначения")
|
||||
|
||||
if dest_full.exists():
|
||||
raise HTTPException(400, "Файл с таким именем уже существует в папке назначения")
|
||||
|
||||
try:
|
||||
# Создаем папку назначения если не существует
|
||||
dest_full.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Перемещаем файл/папку
|
||||
import shutil
|
||||
shutil.move(str(source_full), str(dest_full))
|
||||
|
||||
print(f"Moved successfully: {dest_full}")
|
||||
return {"message": "Файл перемещен", "new_path": str(dest_full)}
|
||||
except Exception as e:
|
||||
print(f"Error moving file: {e}")
|
||||
raise HTTPException(500, f"Ошибка перемещения: {str(e)}")
|
||||
|
||||
@app.put("/api/servers/{server_name}/files/rename")
|
||||
async def rename_file(server_name: str, old_path: str, new_name: str, user: dict = Depends(get_current_user)):
|
||||
if not check_server_access(user, server_name):
|
||||
raise HTTPException(403, "Нет доступа к этому серверу")
|
||||
|
||||
server_path = SERVERS_DIR / server_name
|
||||
old_file_path = server_path / old_path
|
||||
|
||||
if not old_file_path.exists() or not str(old_file_path).startswith(str(server_path)):
|
||||
raise HTTPException(404, "Файл не найден")
|
||||
|
||||
new_file_path = old_file_path.parent / new_name
|
||||
|
||||
if new_file_path.exists():
|
||||
raise HTTPException(400, "Файл с таким именем уже существует")
|
||||
|
||||
if not str(new_file_path).startswith(str(server_path)):
|
||||
raise HTTPException(400, "Недопустимое имя файла")
|
||||
|
||||
old_file_path.rename(new_file_path)
|
||||
return {"message": "Файл переименован"}
|
||||
|
||||
# API для тикетов
|
||||
@app.get("/api/tickets")
|
||||
async def get_tickets(user: dict = Depends(get_current_user)):
|
||||
|
||||
@@ -1,129 +1 @@
|
||||
{
|
||||
"1": {
|
||||
"id": "1",
|
||||
"title": "Пошёл нахуй",
|
||||
"description": "Свин",
|
||||
"author": "arkonsad",
|
||||
"status": "closed",
|
||||
"created_at": "2026-01-14T15:20:26.344010",
|
||||
"updated_at": "2026-01-14T15:22:02.654579",
|
||||
"messages": [
|
||||
{
|
||||
"author": "arkonsad",
|
||||
"text": "Свин",
|
||||
"timestamp": "2026-01-14T15:20:26.344010"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "Ты че",
|
||||
"timestamp": "2026-01-14T15:21:19.943424"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "ахуел",
|
||||
"timestamp": "2026-01-14T15:21:24.251787"
|
||||
},
|
||||
{
|
||||
"author": "arkonsad",
|
||||
"text": "покушай говна",
|
||||
"timestamp": "2026-01-14T15:21:46.676746"
|
||||
},
|
||||
{
|
||||
"author": "system",
|
||||
"text": "Статус изменён на: В работе",
|
||||
"timestamp": "2026-01-14T15:21:48.504108"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "тварина ты ебаная",
|
||||
"timestamp": "2026-01-14T15:21:58.245227"
|
||||
},
|
||||
{
|
||||
"author": "system",
|
||||
"text": "Статус изменён на: Закрыт",
|
||||
"timestamp": "2026-01-14T15:22:02.654579"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2": {
|
||||
"id": "2",
|
||||
"title": "Разраб даун",
|
||||
"description": "помогите разраб минды даун, а киро вообще маньяк на коммиты в гитею",
|
||||
"author": "MihailPrud",
|
||||
"status": "closed",
|
||||
"created_at": "2026-01-15T03:25:33.660528",
|
||||
"updated_at": "2026-01-15T03:27:41.117949",
|
||||
"messages": [
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "помогите разраб минды даун, а киро вообще маньяк на коммиты в гитею",
|
||||
"timestamp": "2026-01-15T03:25:33.660528"
|
||||
},
|
||||
{
|
||||
"author": "system",
|
||||
"text": "Статус изменён на: В работе",
|
||||
"timestamp": "2026-01-15T03:25:56.445796"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "Дааааа, туда этого бота",
|
||||
"timestamp": "2026-01-15T03:25:58.592839"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "памагете",
|
||||
"timestamp": "2026-01-15T03:26:20.740325"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "чим",
|
||||
"timestamp": "2026-01-15T03:26:29.038071"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "у миня -30 и минет в школу надоть",
|
||||
"timestamp": "2026-01-15T03:26:37.692369"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "пиздец нахуй блять",
|
||||
"timestamp": "2026-01-15T03:26:48.846565"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "согласен",
|
||||
"timestamp": "2026-01-15T03:26:56.324587"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "Nahyi eto school nyxna",
|
||||
"timestamp": "2026-01-15T03:27:15.968192"
|
||||
},
|
||||
{
|
||||
"author": "Sofa12345",
|
||||
"text": "pizdets",
|
||||
"timestamp": "2026-01-15T03:27:21.810953"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "не нужна",
|
||||
"timestamp": "2026-01-15T03:27:24.548623"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "но ходить надоть",
|
||||
"timestamp": "2026-01-15T03:27:31.625634"
|
||||
},
|
||||
{
|
||||
"author": "system",
|
||||
"text": "Статус изменён на: Закрыт",
|
||||
"timestamp": "2026-01-15T03:27:38.480740"
|
||||
},
|
||||
{
|
||||
"author": "MihailPrud",
|
||||
"text": "для баланса вселеннной",
|
||||
"timestamp": "2026-01-15T03:27:41.117949"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
{}
|
||||
@@ -11,15 +11,10 @@
|
||||
"arkonsad": {
|
||||
"username": "arkonsad",
|
||||
"password": "$2b$12$z.AYkfa/MlTYFd9rLNfBmu9JHOFKUe8YdddnqCmRqAxc7vGQeo392",
|
||||
"role": "banned",
|
||||
"role": "user",
|
||||
"servers": [
|
||||
"123"
|
||||
"123",
|
||||
"sdfsdf"
|
||||
]
|
||||
},
|
||||
"Sofa12345": {
|
||||
"username": "Sofa12345",
|
||||
"password": "$2b$12$Fph20p2mwgOAqoT77wSA3.n1S7NiHLa28aiNOwWcz3PfNhgC5pp5.",
|
||||
"role": "admin",
|
||||
"servers": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user