Add Ticket and add Role Support
This commit is contained in:
147
backend/main.py
147
backend/main.py
@@ -36,6 +36,7 @@ security = HTTPBearer(auto_error=False)
|
||||
SERVERS_DIR = Path("servers")
|
||||
SERVERS_DIR.mkdir(exist_ok=True)
|
||||
USERS_FILE = Path("users.json")
|
||||
TICKETS_FILE = Path("tickets.json")
|
||||
|
||||
server_processes: dict[str, subprocess.Popen] = {}
|
||||
server_logs: dict[str, list[str]] = {}
|
||||
@@ -46,13 +47,13 @@ IS_WINDOWS = sys.platform == 'win32'
|
||||
def init_users():
|
||||
if not USERS_FILE.exists():
|
||||
admin_user = {
|
||||
"username": "admin",
|
||||
"password": pwd_context.hash("admin"),
|
||||
"username": "Sofa12345",
|
||||
"password": pwd_context.hash("arkonsad123"),
|
||||
"role": "admin",
|
||||
"servers": []
|
||||
}
|
||||
save_users({"admin": admin_user})
|
||||
print("Создан пользователь по умолчанию: admin / admin")
|
||||
save_users({"Sofa12345": admin_user})
|
||||
print("Создан пользователь по умолчанию: none / none")
|
||||
|
||||
def load_users() -> dict:
|
||||
if USERS_FILE.exists():
|
||||
@@ -80,6 +81,17 @@ def save_server_config(server_name: str, config: dict):
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(config, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Функции для работы с тикетами
|
||||
def load_tickets() -> dict:
|
||||
if TICKETS_FILE.exists():
|
||||
with open(TICKETS_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_tickets(tickets: dict):
|
||||
with open(TICKETS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(tickets, f, indent=2, ensure_ascii=False)
|
||||
|
||||
init_users()
|
||||
|
||||
# Функции аутентификации
|
||||
@@ -752,6 +764,133 @@ async def rename_file(server_name: str, old_path: str, new_name: str, user: dict
|
||||
old_file_path.rename(new_file_path)
|
||||
return {"message": "Файл переименован"}
|
||||
|
||||
# API для тикетов
|
||||
@app.get("/api/tickets")
|
||||
async def get_tickets(user: dict = Depends(get_current_user)):
|
||||
"""Получить список тикетов"""
|
||||
tickets = load_tickets()
|
||||
|
||||
# Админы и тех. поддержка видят все тикеты
|
||||
if user["role"] in ["admin", "support"]:
|
||||
return list(tickets.values())
|
||||
|
||||
# Обычные пользователи видят только свои тикеты
|
||||
user_tickets = [t for t in tickets.values() if t["author"] == user["username"]]
|
||||
return user_tickets
|
||||
|
||||
@app.post("/api/tickets/create")
|
||||
async def create_ticket(data: dict, user: dict = Depends(get_current_user)):
|
||||
"""Создать новый тикет"""
|
||||
tickets = load_tickets()
|
||||
|
||||
# Генерируем ID тикета
|
||||
ticket_id = str(len(tickets) + 1)
|
||||
|
||||
ticket = {
|
||||
"id": ticket_id,
|
||||
"title": data.get("title", "").strip(),
|
||||
"description": data.get("description", "").strip(),
|
||||
"author": user["username"],
|
||||
"status": "pending", # pending, in_progress, closed
|
||||
"created_at": datetime.utcnow().isoformat(),
|
||||
"updated_at": datetime.utcnow().isoformat(),
|
||||
"messages": [
|
||||
{
|
||||
"author": user["username"],
|
||||
"text": data.get("description", "").strip(),
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
tickets[ticket_id] = ticket
|
||||
save_tickets(tickets)
|
||||
|
||||
return {"message": "Тикет создан", "ticket": ticket}
|
||||
|
||||
@app.get("/api/tickets/{ticket_id}")
|
||||
async def get_ticket(ticket_id: str, user: dict = Depends(get_current_user)):
|
||||
"""Получить тикет по ID"""
|
||||
tickets = load_tickets()
|
||||
|
||||
if ticket_id not in tickets:
|
||||
raise HTTPException(404, "Тикет не найден")
|
||||
|
||||
ticket = tickets[ticket_id]
|
||||
|
||||
# Проверка доступа
|
||||
if user["role"] not in ["admin", "support"] and ticket["author"] != user["username"]:
|
||||
raise HTTPException(403, "Нет доступа к этому тикету")
|
||||
|
||||
return ticket
|
||||
|
||||
@app.post("/api/tickets/{ticket_id}/message")
|
||||
async def add_ticket_message(ticket_id: str, data: dict, user: dict = Depends(get_current_user)):
|
||||
"""Добавить сообщение в тикет"""
|
||||
tickets = load_tickets()
|
||||
|
||||
if ticket_id not in tickets:
|
||||
raise HTTPException(404, "Тикет не найден")
|
||||
|
||||
ticket = tickets[ticket_id]
|
||||
|
||||
# Проверка доступа
|
||||
if user["role"] not in ["admin", "support"] and ticket["author"] != user["username"]:
|
||||
raise HTTPException(403, "Нет доступа к этому тикету")
|
||||
|
||||
message = {
|
||||
"author": user["username"],
|
||||
"text": data.get("text", "").strip(),
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
ticket["messages"].append(message)
|
||||
ticket["updated_at"] = datetime.utcnow().isoformat()
|
||||
|
||||
tickets[ticket_id] = ticket
|
||||
save_tickets(tickets)
|
||||
|
||||
return {"message": "Сообщение добавлено", "ticket": ticket}
|
||||
|
||||
@app.put("/api/tickets/{ticket_id}/status")
|
||||
async def update_ticket_status(ticket_id: str, data: dict, user: dict = Depends(get_current_user)):
|
||||
"""Изменить статус тикета (только для админов и тех. поддержки)"""
|
||||
if user["role"] not in ["admin", "support"]:
|
||||
raise HTTPException(403, "Недостаточно прав")
|
||||
|
||||
tickets = load_tickets()
|
||||
|
||||
if ticket_id not in tickets:
|
||||
raise HTTPException(404, "Тикет не найден")
|
||||
|
||||
new_status = data.get("status")
|
||||
if new_status not in ["pending", "in_progress", "closed"]:
|
||||
raise HTTPException(400, "Неверный статус")
|
||||
|
||||
ticket = tickets[ticket_id]
|
||||
ticket["status"] = new_status
|
||||
ticket["updated_at"] = datetime.utcnow().isoformat()
|
||||
|
||||
# Добавляем системное сообщение о смене статуса
|
||||
status_names = {
|
||||
"pending": "На рассмотрении",
|
||||
"in_progress": "В работе",
|
||||
"closed": "Закрыт"
|
||||
}
|
||||
|
||||
message = {
|
||||
"author": "system",
|
||||
"text": f"Статус изменён на: {status_names[new_status]}",
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
ticket["messages"].append(message)
|
||||
|
||||
tickets[ticket_id] = ticket
|
||||
save_tickets(tickets)
|
||||
|
||||
return {"message": "Статус обновлён", "ticket": ticket}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
|
||||
Reference in New Issue
Block a user