Change drone.yml
This commit is contained in:
136
.drone.yml
136
.drone.yml
@@ -117,7 +117,7 @@ steps:
|
|||||||
- push
|
- push
|
||||||
- tag
|
- tag
|
||||||
|
|
||||||
# Сканирование образа на уязвимости (опционально)
|
# Сканирование образа на уязвимости
|
||||||
- name: scan-image
|
- name: scan-image
|
||||||
image: aquasec/trivy
|
image: aquasec/trivy
|
||||||
commands:
|
commands:
|
||||||
@@ -128,137 +128,3 @@ steps:
|
|||||||
- tag
|
- tag
|
||||||
depends_on:
|
depends_on:
|
||||||
- build-and-push
|
- build-and-push
|
||||||
|
|
||||||
# Уведомление об успешной сборке (опционально)
|
|
||||||
- name: notify-success
|
|
||||||
image: plugins/slack
|
|
||||||
settings:
|
|
||||||
webhook:
|
|
||||||
from_secret: slack_webhook
|
|
||||||
channel: deployments
|
|
||||||
username: drone
|
|
||||||
template: >
|
|
||||||
✅ Build #{{build.number}} succeeded!
|
|
||||||
|
|
||||||
Repository: {{repo.name}}
|
|
||||||
Branch: {{build.branch}}
|
|
||||||
Commit: {{build.commit}}
|
|
||||||
Author: {{build.author}}
|
|
||||||
|
|
||||||
Docker image: registry.example.com/mc-panel:{{build.commit}}
|
|
||||||
when:
|
|
||||||
status:
|
|
||||||
- success
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
- tag
|
|
||||||
depends_on:
|
|
||||||
- build-and-push
|
|
||||||
|
|
||||||
# Уведомление об ошибке (опционально)
|
|
||||||
- name: notify-failure
|
|
||||||
image: plugins/slack
|
|
||||||
settings:
|
|
||||||
webhook:
|
|
||||||
from_secret: slack_webhook
|
|
||||||
channel: deployments
|
|
||||||
username: drone
|
|
||||||
template: >
|
|
||||||
❌ Build #{{build.number}} failed!
|
|
||||||
|
|
||||||
Repository: {{repo.name}}
|
|
||||||
Branch: {{build.branch}}
|
|
||||||
Commit: {{build.commit}}
|
|
||||||
Author: {{build.author}}
|
|
||||||
|
|
||||||
Link: {{build.link}}
|
|
||||||
when:
|
|
||||||
status:
|
|
||||||
- failure
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
- tag
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: deploy-staging
|
|
||||||
|
|
||||||
# Пайплайн для деплоя на staging (опционально)
|
|
||||||
trigger:
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
branch:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- build-and-publish
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: deploy-to-staging
|
|
||||||
image: appleboy/drone-ssh
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: staging_host
|
|
||||||
username:
|
|
||||||
from_secret: staging_username
|
|
||||||
key:
|
|
||||||
from_secret: staging_ssh_key
|
|
||||||
port: 22
|
|
||||||
script:
|
|
||||||
- cd /opt/mc-panel
|
|
||||||
- docker-compose pull
|
|
||||||
- docker-compose up -d
|
|
||||||
- docker-compose ps
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: deploy-production
|
|
||||||
|
|
||||||
# Пайплайн для деплоя на production (только для тегов)
|
|
||||||
trigger:
|
|
||||||
event:
|
|
||||||
- tag
|
|
||||||
ref:
|
|
||||||
- refs/tags/v*
|
|
||||||
|
|
||||||
depends_on:
|
|
||||||
- build-and-publish
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: deploy-to-production
|
|
||||||
image: appleboy/drone-ssh
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: production_host
|
|
||||||
username:
|
|
||||||
from_secret: production_username
|
|
||||||
key:
|
|
||||||
from_secret: production_ssh_key
|
|
||||||
port: 22
|
|
||||||
script:
|
|
||||||
- cd /opt/mc-panel
|
|
||||||
- docker-compose pull
|
|
||||||
- docker-compose up -d
|
|
||||||
- docker-compose ps
|
|
||||||
- echo "Deployed version ${DRONE_TAG}"
|
|
||||||
|
|
||||||
- name: notify-production-deploy
|
|
||||||
image: plugins/slack
|
|
||||||
settings:
|
|
||||||
webhook:
|
|
||||||
from_secret: slack_webhook
|
|
||||||
channel: deployments
|
|
||||||
username: drone
|
|
||||||
template: >
|
|
||||||
🚀 Production deployment successful!
|
|
||||||
|
|
||||||
Version: {{build.tag}}
|
|
||||||
Repository: {{repo.name}}
|
|
||||||
Author: {{build.author}}
|
|
||||||
|
|
||||||
Docker image: registry.example.com/mc-panel:{{build.tag}}
|
|
||||||
when:
|
|
||||||
status:
|
|
||||||
- success
|
|
||||||
|
|||||||
391
DRONE_SIMPLIFIED.md
Normal file
391
DRONE_SIMPLIFIED.md
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
# 🚀 Упрощённый Drone CI/CD
|
||||||
|
|
||||||
|
**Дата:** 15 января 2026
|
||||||
|
**Статус:** УПРОЩЕНО ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Что изменилось
|
||||||
|
|
||||||
|
### До изменения
|
||||||
|
|
||||||
|
**4 пайплайна:**
|
||||||
|
1. code-quality - Проверка качества кода
|
||||||
|
2. build-and-publish - Сборка и публикация образа
|
||||||
|
3. deploy-staging - Деплой на staging
|
||||||
|
4. deploy-production - Деплой на production
|
||||||
|
|
||||||
|
**Уведомления:**
|
||||||
|
- notify-success - Уведомление об успешной сборке
|
||||||
|
- notify-failure - Уведомление об ошибке
|
||||||
|
- notify-production-deploy - Уведомление о деплое
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### После изменения
|
||||||
|
|
||||||
|
**2 пайплайна:**
|
||||||
|
1. code-quality - Проверка качества кода
|
||||||
|
2. build-and-publish - Сборка и публикация образа
|
||||||
|
|
||||||
|
**Уведомления:** Удалены
|
||||||
|
|
||||||
|
**Деплой пайплайны:** Удалены
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Оставшиеся пайплайны
|
||||||
|
|
||||||
|
### 1. code-quality
|
||||||
|
|
||||||
|
**Назначение:** Проверка качества и безопасности кода
|
||||||
|
|
||||||
|
**Триггеры:**
|
||||||
|
- Push в любую ветку
|
||||||
|
- Pull Request
|
||||||
|
|
||||||
|
**Шаги:**
|
||||||
|
1. **python-lint** - Проверка Python кода
|
||||||
|
- flake8 (синтаксис и стиль)
|
||||||
|
- pylint (качество кода)
|
||||||
|
- black (форматирование)
|
||||||
|
- isort (сортировка импортов)
|
||||||
|
|
||||||
|
2. **frontend-lint** - Проверка JavaScript/React кода
|
||||||
|
- ESLint (синтаксис и стиль)
|
||||||
|
- Prettier (форматирование)
|
||||||
|
|
||||||
|
3. **python-security** - Проверка безопасности Python
|
||||||
|
- safety (известные уязвимости)
|
||||||
|
- bandit (security linter)
|
||||||
|
|
||||||
|
4. **frontend-security** - Проверка безопасности Node.js
|
||||||
|
- npm audit (уязвимости зависимостей)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. build-and-publish
|
||||||
|
|
||||||
|
**Назначение:** Сборка и публикация Docker образа
|
||||||
|
|
||||||
|
**Триггеры:**
|
||||||
|
- Push в ветки: main, master, develop
|
||||||
|
- Push тега
|
||||||
|
|
||||||
|
**Зависимости:**
|
||||||
|
- Запускается только после успешного code-quality
|
||||||
|
|
||||||
|
**Шаги:**
|
||||||
|
1. **build-and-push** - Сборка и публикация образа
|
||||||
|
- Сборка Docker образа
|
||||||
|
- Публикация в registry
|
||||||
|
- Автоматическое тегирование
|
||||||
|
|
||||||
|
2. **scan-image** - Сканирование на уязвимости
|
||||||
|
- Trivy сканирование
|
||||||
|
- Проверка HIGH и CRITICAL уязвимостей
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗑️ Удалённые пайплайны
|
||||||
|
|
||||||
|
### deploy-staging
|
||||||
|
**Причина удаления:** Упрощение конфигурации
|
||||||
|
|
||||||
|
**Что делал:**
|
||||||
|
- SSH подключение к staging серверу
|
||||||
|
- Обновление Docker образа
|
||||||
|
- Перезапуск контейнеров
|
||||||
|
|
||||||
|
**Альтернатива:** Ручной деплой через SSH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### deploy-production
|
||||||
|
**Причина удаления:** Упрощение конфигурации
|
||||||
|
|
||||||
|
**Что делал:**
|
||||||
|
- SSH подключение к production серверу
|
||||||
|
- Обновление Docker образа
|
||||||
|
- Перезапуск контейнеров
|
||||||
|
- Уведомление в Slack
|
||||||
|
|
||||||
|
**Альтернатива:** Ручной деплой через SSH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗑️ Удалённые уведомления
|
||||||
|
|
||||||
|
### notify-success
|
||||||
|
**Что делал:** Отправка уведомления в Slack об успешной сборке
|
||||||
|
|
||||||
|
### notify-failure
|
||||||
|
**Что делал:** Отправка уведомления в Slack об ошибке сборки
|
||||||
|
|
||||||
|
### notify-production-deploy
|
||||||
|
**Что делал:** Отправка уведомления в Slack о деплое на production
|
||||||
|
|
||||||
|
**Причина удаления:** Упрощение, не требуется настройка Slack webhook
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Настройка
|
||||||
|
|
||||||
|
### Необходимые Drone Secrets
|
||||||
|
|
||||||
|
Для работы оставшихся пайплайнов нужны только:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Docker Registry
|
||||||
|
docker_username=your_username
|
||||||
|
docker_password=your_password
|
||||||
|
```
|
||||||
|
|
||||||
|
### Удалённые Secrets (больше не нужны)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Slack (удалено)
|
||||||
|
slack_webhook
|
||||||
|
|
||||||
|
# SSH для staging (удалено)
|
||||||
|
staging_host
|
||||||
|
staging_username
|
||||||
|
staging_ssh_key
|
||||||
|
|
||||||
|
# SSH для production (удалено)
|
||||||
|
production_host
|
||||||
|
production_username
|
||||||
|
production_ssh_key
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Как использовать
|
||||||
|
|
||||||
|
### Автоматическая проверка кода
|
||||||
|
|
||||||
|
При каждом push или pull request:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Update code"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
1. ✅ Запускается code-quality
|
||||||
|
2. ✅ Проверяется качество кода
|
||||||
|
3. ✅ Проверяется безопасность
|
||||||
|
4. ✅ Если всё ОК → запускается build-and-publish
|
||||||
|
5. ✅ Собирается Docker образ
|
||||||
|
6. ✅ Публикуется в registry
|
||||||
|
7. ✅ Сканируется на уязвимости
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ручной деплой на staging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH на staging сервер
|
||||||
|
ssh user@staging-server
|
||||||
|
|
||||||
|
# Обновление
|
||||||
|
cd /opt/mc-panel
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ручной деплой на production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH на production сервер
|
||||||
|
ssh user@production-server
|
||||||
|
|
||||||
|
# Обновление
|
||||||
|
cd /opt/mc-panel
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Сравнение
|
||||||
|
|
||||||
|
### До упрощения
|
||||||
|
|
||||||
|
```
|
||||||
|
Push → code-quality → build-and-publish → deploy-staging
|
||||||
|
↓
|
||||||
|
notify-success
|
||||||
|
↓
|
||||||
|
notify-failure
|
||||||
|
|
||||||
|
Tag → code-quality → build-and-publish → deploy-production
|
||||||
|
↓
|
||||||
|
notify-production-deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
**Требуется:**
|
||||||
|
- 7 Drone secrets
|
||||||
|
- Настройка Slack
|
||||||
|
- Настройка SSH для 2 серверов
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### После упрощения
|
||||||
|
|
||||||
|
```
|
||||||
|
Push → code-quality → build-and-publish
|
||||||
|
|
||||||
|
Tag → code-quality → build-and-publish
|
||||||
|
```
|
||||||
|
|
||||||
|
**Требуется:**
|
||||||
|
- 2 Drone secrets (docker_username, docker_password)
|
||||||
|
- Ручной деплой через SSH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Преимущества упрощения
|
||||||
|
|
||||||
|
### Меньше настроек
|
||||||
|
- ❌ Не нужен Slack webhook
|
||||||
|
- ❌ Не нужны SSH ключи
|
||||||
|
- ❌ Не нужны настройки серверов
|
||||||
|
- ✅ Только Docker registry
|
||||||
|
|
||||||
|
### Больше контроля
|
||||||
|
- ✅ Ручной деплой = больше контроля
|
||||||
|
- ✅ Можно проверить перед деплоем
|
||||||
|
- ✅ Можно откатить если нужно
|
||||||
|
|
||||||
|
### Проще поддержка
|
||||||
|
- ✅ Меньше кода
|
||||||
|
- ✅ Меньше зависимостей
|
||||||
|
- ✅ Проще понять
|
||||||
|
- ✅ Проще отладить
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Workflow
|
||||||
|
|
||||||
|
### Разработка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Разработка
|
||||||
|
git checkout -b feature/new-feature
|
||||||
|
# ... код ...
|
||||||
|
git commit -m "Add new feature"
|
||||||
|
git push origin feature/new-feature
|
||||||
|
|
||||||
|
# 2. Pull Request
|
||||||
|
# Создать PR на GitHub/GitLab
|
||||||
|
# Drone автоматически проверит код
|
||||||
|
|
||||||
|
# 3. Merge
|
||||||
|
# После одобрения PR
|
||||||
|
git checkout main
|
||||||
|
git merge feature/new-feature
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# 4. Автоматическая сборка
|
||||||
|
# Drone соберёт и опубликует образ
|
||||||
|
|
||||||
|
# 5. Ручной деплой
|
||||||
|
ssh user@server
|
||||||
|
cd /opt/mc-panel
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Production Release
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Создать тег
|
||||||
|
git tag -a v1.1.0 -m "Release 1.1.0"
|
||||||
|
git push origin v1.1.0
|
||||||
|
|
||||||
|
# 2. Автоматическая сборка
|
||||||
|
# Drone соберёт образ с тегом v1.1.0
|
||||||
|
|
||||||
|
# 3. Ручной деплой на production
|
||||||
|
ssh user@production-server
|
||||||
|
cd /opt/mc-panel
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Файл .drone.yml
|
||||||
|
|
||||||
|
### Структура
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
# Пайплайн 1: Проверка качества
|
||||||
|
kind: pipeline
|
||||||
|
name: code-quality
|
||||||
|
trigger: push, pull_request
|
||||||
|
steps:
|
||||||
|
- python-lint
|
||||||
|
- frontend-lint
|
||||||
|
- python-security
|
||||||
|
- frontend-security
|
||||||
|
|
||||||
|
---
|
||||||
|
# Пайплайн 2: Сборка и публикация
|
||||||
|
kind: pipeline
|
||||||
|
name: build-and-publish
|
||||||
|
trigger: push (main/master/develop), tag
|
||||||
|
depends_on: code-quality
|
||||||
|
steps:
|
||||||
|
- build-and-push
|
||||||
|
- scan-image
|
||||||
|
```
|
||||||
|
|
||||||
|
### Размер файла
|
||||||
|
|
||||||
|
**До:** ~300 строк
|
||||||
|
**После:** ~120 строк
|
||||||
|
**Уменьшение:** 60%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Итог
|
||||||
|
|
||||||
|
**Конфигурация упрощена!** ✅
|
||||||
|
|
||||||
|
### Что осталось:
|
||||||
|
- ✅ Проверка качества кода
|
||||||
|
- ✅ Проверка безопасности
|
||||||
|
- ✅ Сборка Docker образа
|
||||||
|
- ✅ Публикация в registry
|
||||||
|
- ✅ Сканирование на уязвимости
|
||||||
|
|
||||||
|
### Что удалено:
|
||||||
|
- ❌ Автоматический деплой
|
||||||
|
- ❌ Уведомления в Slack
|
||||||
|
- ❌ SSH настройки
|
||||||
|
|
||||||
|
### Результат:
|
||||||
|
- 🎯 Проще настроить
|
||||||
|
- 🎯 Проще поддерживать
|
||||||
|
- 🎯 Больше контроля над деплоем
|
||||||
|
- 🎯 Меньше зависимостей
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Версия:** 1.1.0
|
||||||
|
**Дата:** 15 января 2026
|
||||||
|
**Статус:** УПРОЩЕНО ✅
|
||||||
|
|
||||||
|
**Меньше сложности - больше контроля!** 🚀
|
||||||
|
|
||||||
134
FIX_BASEMODEL.md
134
FIX_BASEMODEL.md
@@ -1,134 +0,0 @@
|
|||||||
# 🔧 Исправление ошибки BaseModel
|
|
||||||
|
|
||||||
**Ошибка:** `NameError: name 'BaseModel' is not defined`
|
|
||||||
**Статус:** ИСПРАВЛЕНО ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Проблема
|
|
||||||
|
|
||||||
При запуске `backend/main.py` возникала ошибка:
|
|
||||||
|
|
||||||
```
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "backend\main.py", line 1655, in <module>
|
|
||||||
class RoleChange(BaseModel):
|
|
||||||
^^^^^^^^^
|
|
||||||
NameError: name 'BaseModel' is not defined
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Решение
|
|
||||||
|
|
||||||
Добавлен импорт `BaseModel` из `pydantic` в начало файла `backend/main.py`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from pydantic import BaseModel
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Что было сделано
|
|
||||||
|
|
||||||
### Изменение в backend/main.py
|
|
||||||
|
|
||||||
**Было:**
|
|
||||||
```python
|
|
||||||
from fastapi import FastAPI, WebSocket, UploadFile, File, HTTPException, Depends, status, Request
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
from fastapi.responses import FileResponse, RedirectResponse
|
|
||||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
||||||
import asyncio
|
|
||||||
```
|
|
||||||
|
|
||||||
**Стало:**
|
|
||||||
```python
|
|
||||||
from fastapi import FastAPI, WebSocket, UploadFile, File, HTTPException, Depends, status, Request
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
from fastapi.responses import FileResponse, RedirectResponse
|
|
||||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
||||||
from pydantic import BaseModel # ← Добавлено
|
|
||||||
import asyncio
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Запуск
|
|
||||||
|
|
||||||
Теперь можно запустить панель:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd backend
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Или используйте:
|
|
||||||
```bash
|
|
||||||
RESTART_ALL.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Проверка
|
|
||||||
|
|
||||||
После запуска вы должны увидеть:
|
|
||||||
|
|
||||||
```
|
|
||||||
INFO: Started server process [PID]
|
|
||||||
INFO: Waiting for application startup.
|
|
||||||
INFO: Application startup complete.
|
|
||||||
INFO: Uvicorn running on http://0.0.0.0:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
Без ошибок! ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Что такое BaseModel?
|
|
||||||
|
|
||||||
`BaseModel` - это базовый класс из библиотеки `pydantic`, который используется для создания моделей данных с валидацией.
|
|
||||||
|
|
||||||
**Используется для:**
|
|
||||||
- Валидация входных данных API
|
|
||||||
- Автоматическая генерация документации
|
|
||||||
- Сериализация/десериализация JSON
|
|
||||||
|
|
||||||
**Примеры в коде:**
|
|
||||||
```python
|
|
||||||
class RoleChange(BaseModel):
|
|
||||||
role: str
|
|
||||||
|
|
||||||
class BanRequest(BaseModel):
|
|
||||||
reason: str = "Заблокирован администратором"
|
|
||||||
|
|
||||||
class ServerAccess(BaseModel):
|
|
||||||
server_name: str
|
|
||||||
|
|
||||||
class PermissionsUpdate(BaseModel):
|
|
||||||
permissions: dict
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 Почему возникла ошибка?
|
|
||||||
|
|
||||||
При добавлении новых эндпоинтов управления пользователями были созданы новые модели данных (`RoleChange`, `BanRequest`, и т.д.), но импорт `BaseModel` не был добавлен.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✨ Готово!
|
|
||||||
|
|
||||||
Ошибка исправлена, панель должна запускаться без проблем.
|
|
||||||
|
|
||||||
**Запустите:**
|
|
||||||
```bash
|
|
||||||
cd backend
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Дата исправления:** 15 января 2026
|
|
||||||
**Статус:** РАБОТАЕТ ✅
|
|
||||||
|
|
||||||
431
MULTIPLE_OWNERS.md
Normal file
431
MULTIPLE_OWNERS.md
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
# 👑 Несколько владельцев
|
||||||
|
|
||||||
|
**Дата:** 15 января 2026
|
||||||
|
**Статус:** РЕАЛИЗОВАНО ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Что изменилось
|
||||||
|
|
||||||
|
### До изменения
|
||||||
|
|
||||||
|
**Ограничение:** Мог быть только ОДИН владелец
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ При назначении нового owner, старый owner автоматически становился admin
|
||||||
|
❌ Нельзя было удалить владельца
|
||||||
|
❌ Нельзя было заблокировать владельца
|
||||||
|
```
|
||||||
|
|
||||||
|
**Проблема:** Если нужно несколько администраторов с полными правами, приходилось использовать роль admin, у которой нет права изменять роли.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### После изменения
|
||||||
|
|
||||||
|
**Возможность:** Может быть НЕСКОЛЬКО владельцев
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ Можно назначить несколько пользователей с ролью owner
|
||||||
|
✅ Можно удалить владельца (если их больше одного)
|
||||||
|
✅ Можно заблокировать владельца (если их больше одного)
|
||||||
|
✅ Всегда должен остаться хотя бы один владелец
|
||||||
|
```
|
||||||
|
|
||||||
|
**Преимущество:** Несколько человек могут иметь полный контроль над панелью.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Новая логика
|
||||||
|
|
||||||
|
### Назначение владельца
|
||||||
|
|
||||||
|
**Было:**
|
||||||
|
```python
|
||||||
|
# Если назначается новый owner, текущий owner становится admin
|
||||||
|
if role_data.role == "owner":
|
||||||
|
for user in users.values():
|
||||||
|
if user.get("role") == "owner":
|
||||||
|
user["role"] = "admin" # Понижение роли
|
||||||
|
```
|
||||||
|
|
||||||
|
**Стало:**
|
||||||
|
```python
|
||||||
|
# Разрешаем несколько владельцев
|
||||||
|
# Просто назначаем роль без изменения других владельцев
|
||||||
|
users[username]["role"] = role_data.role
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Удаление владельца
|
||||||
|
|
||||||
|
**Было:**
|
||||||
|
```python
|
||||||
|
if users[username].get("role") == "owner":
|
||||||
|
raise HTTPException(400, "Нельзя удалить владельца")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Стало:**
|
||||||
|
```python
|
||||||
|
if users[username].get("role") == "owner":
|
||||||
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(400, "Нельзя удалить последнего владельца")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Логика:**
|
||||||
|
- Если владельцев больше одного → можно удалить
|
||||||
|
- Если владелец последний → нельзя удалить
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Блокировка владельца
|
||||||
|
|
||||||
|
**Было:**
|
||||||
|
```python
|
||||||
|
if users[username].get("role") == "owner":
|
||||||
|
raise HTTPException(400, "Нельзя заблокировать владельца")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Стало:**
|
||||||
|
```python
|
||||||
|
if users[username].get("role") == "owner":
|
||||||
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(400, "Нельзя заблокировать последнего владельца")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Логика:**
|
||||||
|
- Если владельцев больше одного → можно заблокировать
|
||||||
|
- Если владелец последний → нельзя заблокировать
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Примеры использования
|
||||||
|
|
||||||
|
### Сценарий 1: Назначить второго владельца
|
||||||
|
|
||||||
|
**Текущее состояние:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"Admin1": {"role": "admin"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Действие:** Назначить Admin1 владельцем
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"Admin1": {"role": "owner"} // Теперь тоже владелец!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Оба пользователя имеют полные права!** ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Сценарий 2: Удалить одного из владельцев
|
||||||
|
|
||||||
|
**Текущее состояние:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"Admin1": {"role": "owner"},
|
||||||
|
"User1": {"role": "user"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Действие:** Удалить Admin1
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"User1": {"role": "user"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Успешно!** Root остался владельцем ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Сценарий 3: Попытка удалить последнего владельца
|
||||||
|
|
||||||
|
**Текущее состояние:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"User1": {"role": "user"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Действие:** Удалить Root
|
||||||
|
|
||||||
|
**Результат:**
|
||||||
|
```
|
||||||
|
❌ Ошибка: "Нельзя удалить последнего владельца. Должен остаться хотя бы один владелец."
|
||||||
|
```
|
||||||
|
|
||||||
|
**Защита от потери контроля!** 🔒
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Сценарий 4: Три владельца
|
||||||
|
|
||||||
|
**Возможно:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Root": {"role": "owner"},
|
||||||
|
"Admin1": {"role": "owner"},
|
||||||
|
"Admin2": {"role": "owner"},
|
||||||
|
"User1": {"role": "user"}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Все три владельца имеют:**
|
||||||
|
- ✅ Управление пользователями
|
||||||
|
- ✅ Изменение ролей
|
||||||
|
- ✅ Удаление пользователей
|
||||||
|
- ✅ Просмотр всех ресурсов
|
||||||
|
- ✅ Все права
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Как использовать
|
||||||
|
|
||||||
|
### Назначить нового владельца
|
||||||
|
|
||||||
|
1. Войдите как владелец
|
||||||
|
2. Нажмите "Управление"
|
||||||
|
3. Найдите пользователя
|
||||||
|
4. Нажмите "Роль"
|
||||||
|
5. Выберите "Владелец"
|
||||||
|
6. Готово! Теперь два владельца
|
||||||
|
|
||||||
|
### Понизить владельца до админа
|
||||||
|
|
||||||
|
1. Войдите как владелец
|
||||||
|
2. Нажмите "Управление"
|
||||||
|
3. Найдите другого владельца
|
||||||
|
4. Нажмите "Роль"
|
||||||
|
5. Выберите "Администратор"
|
||||||
|
6. Владелец понижен до админа
|
||||||
|
|
||||||
|
### Удалить владельца
|
||||||
|
|
||||||
|
1. Убедитесь что владельцев больше одного
|
||||||
|
2. Войдите как владелец
|
||||||
|
3. Нажмите "Управление"
|
||||||
|
4. Найдите владельца для удаления
|
||||||
|
5. Нажмите кнопку удаления (красная)
|
||||||
|
6. Подтвердите
|
||||||
|
7. Владелец удалён (если их было больше одного)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Правила безопасности
|
||||||
|
|
||||||
|
### Что НЕЛЬЗЯ сделать:
|
||||||
|
|
||||||
|
- ❌ Удалить последнего владельца
|
||||||
|
- ❌ Заблокировать последнего владельца
|
||||||
|
- ❌ Изменить свою роль
|
||||||
|
- ❌ Удалить самого себя
|
||||||
|
- ❌ Заблокировать самого себя
|
||||||
|
|
||||||
|
### Что МОЖНО:
|
||||||
|
|
||||||
|
- ✅ Назначить несколько владельцев
|
||||||
|
- ✅ Удалить владельца (если их больше одного)
|
||||||
|
- ✅ Заблокировать владельца (если их больше одного)
|
||||||
|
- ✅ Понизить владельца до админа
|
||||||
|
- ✅ Повысить админа до владельца
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Сравнение ролей
|
||||||
|
|
||||||
|
### Owner (Владелец) - Несколько человек ✅
|
||||||
|
|
||||||
|
**Права:**
|
||||||
|
- ✅ Управление пользователями
|
||||||
|
- ✅ Изменение ролей (включая назначение других владельцев)
|
||||||
|
- ✅ Удаление пользователей
|
||||||
|
- ✅ Управление серверами
|
||||||
|
- ✅ Просмотр всех ресурсов
|
||||||
|
- ✅ Все права
|
||||||
|
|
||||||
|
**Ограничения:**
|
||||||
|
- Должен быть хотя бы один владелец
|
||||||
|
- Нельзя удалить/заблокировать себя
|
||||||
|
|
||||||
|
### Admin (Администратор) - Несколько человек ✅
|
||||||
|
|
||||||
|
**Права:**
|
||||||
|
- ✅ Управление пользователями
|
||||||
|
- ✅ Управление серверами
|
||||||
|
- ✅ Просмотр всех ресурсов
|
||||||
|
- ❌ Изменение ролей
|
||||||
|
- ❌ Удаление пользователей
|
||||||
|
|
||||||
|
**Отличие от Owner:**
|
||||||
|
- Не может назначать владельцев
|
||||||
|
- Не может удалять пользователей
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 UI изменения
|
||||||
|
|
||||||
|
### Модальное окно изменения роли
|
||||||
|
|
||||||
|
Теперь при выборе "Владелец" не будет предупреждения о понижении текущего владельца:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ Изменить роль: Admin1 │
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ [👑 Владелец] │
|
||||||
|
│ Полный контроль над панелью │
|
||||||
|
│ ⚠️ Может быть несколько │ ← Новое
|
||||||
|
│ │
|
||||||
|
│ [🛡️ Администратор] ← Текущая │
|
||||||
|
│ Управление без изменения │
|
||||||
|
│ ролей │
|
||||||
|
│ │
|
||||||
|
│ [Отмена] │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Список пользователей
|
||||||
|
|
||||||
|
Теперь может быть несколько пользователей с меткой "👑 Владелец":
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Root [👑 Владелец]
|
||||||
|
2. Admin1 [👑 Владелец] ← Новое
|
||||||
|
3. Admin2 [🛡️ Админ]
|
||||||
|
4. User1 [✅ Пользователь]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Технические детали
|
||||||
|
|
||||||
|
### Изменённые файлы
|
||||||
|
|
||||||
|
**Файл:** `backend/main.py`
|
||||||
|
|
||||||
|
**Изменённые эндпоинты:**
|
||||||
|
1. `PUT /api/users/{username}/role` - Убрано автоматическое понижение
|
||||||
|
2. `DELETE /api/users/{username}` - Добавлена проверка количества владельцев
|
||||||
|
3. `POST /api/users/{username}/ban` - Добавлена проверка количества владельцев
|
||||||
|
|
||||||
|
**Добавленная логика:**
|
||||||
|
```python
|
||||||
|
# Подсчёт владельцев
|
||||||
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
|
||||||
|
# Проверка перед удалением/блокировкой
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(400, "Нельзя удалить/заблокировать последнего владельца")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Рекомендации
|
||||||
|
|
||||||
|
### Когда использовать несколько владельцев
|
||||||
|
|
||||||
|
**Хорошие случаи:**
|
||||||
|
- ✅ Несколько администраторов проекта
|
||||||
|
- ✅ Команда разработчиков
|
||||||
|
- ✅ Резервный владелец на случай отсутствия основного
|
||||||
|
- ✅ Разделение ответственности
|
||||||
|
|
||||||
|
**Плохие случаи:**
|
||||||
|
- ❌ Слишком много владельцев (риск безопасности)
|
||||||
|
- ❌ Назначение владельцем ненадёжных пользователей
|
||||||
|
- ❌ Владелец "на пробу"
|
||||||
|
|
||||||
|
### Рекомендуемая структура
|
||||||
|
|
||||||
|
```
|
||||||
|
👑 Owner (2-3 человека) - Основные администраторы
|
||||||
|
↓
|
||||||
|
🛡️ Admin (3-5 человек) - Помощники администраторов
|
||||||
|
↓
|
||||||
|
💬 Support (5-10 человек) - Техническая поддержка
|
||||||
|
↓
|
||||||
|
✅ User (неограниченно) - Обычные пользователи
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Перезапуск
|
||||||
|
|
||||||
|
После изменений перезапустите панель:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RESTART_ALL.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
Или вручную:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Проверка
|
||||||
|
|
||||||
|
### Тест 1: Назначить второго владельца
|
||||||
|
|
||||||
|
1. Войдите как Root
|
||||||
|
2. Управление → MihailPrud → Роль → Владелец
|
||||||
|
3. Проверьте что оба имеют роль owner
|
||||||
|
|
||||||
|
### Тест 2: Попытка удалить единственного владельца
|
||||||
|
|
||||||
|
1. Понизьте всех владельцев кроме одного
|
||||||
|
2. Попытайтесь удалить последнего
|
||||||
|
3. Должна быть ошибка
|
||||||
|
|
||||||
|
### Тест 3: Удаление одного из нескольких владельцев
|
||||||
|
|
||||||
|
1. Назначьте двух владельцев
|
||||||
|
2. Удалите одного
|
||||||
|
3. Должно пройти успешно
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 Итог
|
||||||
|
|
||||||
|
**Теперь можно иметь несколько владельцев!** ✅
|
||||||
|
|
||||||
|
### Преимущества:
|
||||||
|
|
||||||
|
- ✅ Гибкость в управлении
|
||||||
|
- ✅ Резервирование доступа
|
||||||
|
- ✅ Разделение ответственности
|
||||||
|
- ✅ Защита от потери контроля (всегда остаётся хотя бы один владелец)
|
||||||
|
|
||||||
|
### Безопасность:
|
||||||
|
|
||||||
|
- 🔒 Нельзя удалить последнего владельца
|
||||||
|
- 🔒 Нельзя заблокировать последнего владельца
|
||||||
|
- 🔒 Нельзя изменить свою роль
|
||||||
|
- 🔒 Нельзя удалить себя
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Версия:** 1.1.0
|
||||||
|
**Дата:** 15 января 2026
|
||||||
|
**Статус:** РАБОТАЕТ ✅
|
||||||
|
|
||||||
|
**Несколько владельцев - больше контроля!** 👑👑👑
|
||||||
|
|
||||||
24
README.md
24
README.md
@@ -91,6 +91,30 @@ Comprehensive overview всего проекта:
|
|||||||
|
|
||||||
**Полный контроль над всеми ресурсами!** 🖥️
|
**Полный контроль над всеми ресурсами!** 🖥️
|
||||||
|
|
||||||
|
### 👑 [MULTIPLE_OWNERS.md](MULTIPLE_OWNERS.md)
|
||||||
|
**Несколько владельцев**
|
||||||
|
|
||||||
|
Возможность назначить несколько владельцев:
|
||||||
|
- 🎯 Что изменилось
|
||||||
|
- 📊 Новая логика
|
||||||
|
- 💡 Примеры использования
|
||||||
|
- 🔒 Правила безопасности
|
||||||
|
- 🎯 Рекомендации
|
||||||
|
|
||||||
|
**Больше владельцев - больше контроля!** 👑👑
|
||||||
|
|
||||||
|
### 🚀 [DRONE_SIMPLIFIED.md](DRONE_SIMPLIFIED.md)
|
||||||
|
**Упрощённый CI/CD**
|
||||||
|
|
||||||
|
Упрощение Drone конфигурации:
|
||||||
|
- 🎯 Что изменилось (4→2 пайплайна)
|
||||||
|
- 📋 Оставшиеся пайплайны
|
||||||
|
- 🗑️ Удалённые компоненты
|
||||||
|
- 🔧 Настройка
|
||||||
|
- ✅ Преимущества
|
||||||
|
|
||||||
|
**Меньше сложности - больше контроля!** 🔧
|
||||||
|
|
||||||
### 📝 [CHANGELOG.md](CHANGELOG.md)
|
### 📝 [CHANGELOG.md](CHANGELOG.md)
|
||||||
**История изменений**
|
**История изменений**
|
||||||
|
|
||||||
|
|||||||
@@ -445,9 +445,11 @@ async def delete_user(username: str, user: dict = Depends(get_current_user)):
|
|||||||
if username not in users:
|
if username not in users:
|
||||||
raise HTTPException(404, "Пользователь не найден")
|
raise HTTPException(404, "Пользователь не найден")
|
||||||
|
|
||||||
# Нельзя удалить другого владельца
|
# Проверяем, что не удаляем последнего владельца
|
||||||
if users[username]["role"] == "owner":
|
if users[username]["role"] == "owner":
|
||||||
raise HTTPException(400, "Нельзя удалить владельца")
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(400, "Нельзя удалить последнего владельца")
|
||||||
|
|
||||||
del users[username]
|
del users[username]
|
||||||
save_users(users)
|
save_users(users)
|
||||||
@@ -1672,11 +1674,8 @@ async def change_user_role(username: str, role_data: RoleChange, current_user: d
|
|||||||
if role_data.role not in valid_roles:
|
if role_data.role not in valid_roles:
|
||||||
raise HTTPException(status_code=400, detail=f"Неверная роль")
|
raise HTTPException(status_code=400, detail=f"Неверная роль")
|
||||||
|
|
||||||
# Если назначается новый owner, текущий owner становится admin
|
# Разрешаем несколько владельцев (убрано ограничение на одного)
|
||||||
if role_data.role == "owner":
|
# Теперь можно назначить несколько пользователей с ролью owner
|
||||||
for user in users.values():
|
|
||||||
if user.get("role") == "owner":
|
|
||||||
user["role"] = "admin"
|
|
||||||
|
|
||||||
old_role = users[username].get("role", "user")
|
old_role = users[username].get("role", "user")
|
||||||
users[username]["role"] = role_data.role
|
users[username]["role"] = role_data.role
|
||||||
@@ -1733,8 +1732,11 @@ async def ban_user(username: str, ban_data: BanRequest, current_user: dict = Dep
|
|||||||
if username == current_user.get("username"):
|
if username == current_user.get("username"):
|
||||||
raise HTTPException(status_code=400, detail="Нельзя заблокировать самого себя")
|
raise HTTPException(status_code=400, detail="Нельзя заблокировать самого себя")
|
||||||
|
|
||||||
|
# Проверяем, что не блокируем последнего владельца
|
||||||
if users[username].get("role") == "owner":
|
if users[username].get("role") == "owner":
|
||||||
raise HTTPException(status_code=400, detail="Нельзя заблокировать владельца")
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(status_code=400, detail="Нельзя заблокировать последнего владельца. Должен остаться хотя бы один владелец.")
|
||||||
|
|
||||||
users[username]["role"] = "banned"
|
users[username]["role"] = "banned"
|
||||||
users[username]["permissions"] = {
|
users[username]["permissions"] = {
|
||||||
@@ -1786,8 +1788,11 @@ async def delete_user(username: str, current_user: dict = Depends(get_current_us
|
|||||||
if username == current_user.get("username"):
|
if username == current_user.get("username"):
|
||||||
raise HTTPException(status_code=400, detail="Нельзя удалить самого себя")
|
raise HTTPException(status_code=400, detail="Нельзя удалить самого себя")
|
||||||
|
|
||||||
|
# Проверяем, что не удаляем последнего владельца
|
||||||
if users[username].get("role") == "owner":
|
if users[username].get("role") == "owner":
|
||||||
raise HTTPException(status_code=400, detail="Нельзя удалить владельца")
|
owners_count = sum(1 for u in users.values() if u.get("role") == "owner")
|
||||||
|
if owners_count <= 1:
|
||||||
|
raise HTTPException(status_code=400, detail="Нельзя удалить последнего владельца. Должен остаться хотя бы один владелец.")
|
||||||
|
|
||||||
del users[username]
|
del users[username]
|
||||||
save_users_dict(users)
|
save_users_dict(users)
|
||||||
|
|||||||
@@ -1,74 +1 @@
|
|||||||
{
|
{}
|
||||||
"Root": {
|
|
||||||
"username": "Root",
|
|
||||||
"password": "$2b$12$PAaomoUWn3Ip5ov.S/uYPeTIRiDMq7DbA57ahyYQnw3QHT2zuYMlG",
|
|
||||||
"role": "owner",
|
|
||||||
"servers": [],
|
|
||||||
"permissions": {
|
|
||||||
"manage_users": true,
|
|
||||||
"manage_roles": true,
|
|
||||||
"manage_servers": true,
|
|
||||||
"manage_tickets": true,
|
|
||||||
"manage_files": true,
|
|
||||||
"delete_users": true,
|
|
||||||
"view_all_resources": true
|
|
||||||
},
|
|
||||||
"resource_access": {
|
|
||||||
"servers": [],
|
|
||||||
"tickets": [],
|
|
||||||
"files": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MihailPrud": {
|
|
||||||
"username": "MihailPrud",
|
|
||||||
"password": "$2b$12$GfbQN4scE.b.mtUHofWWE.Dn1tQpT1zwLAxeICv90sHP4zGv0dc2G",
|
|
||||||
"role": "user",
|
|
||||||
"servers": [
|
|
||||||
"test",
|
|
||||||
"nya"
|
|
||||||
],
|
|
||||||
"permissions": {
|
|
||||||
"manage_users": false,
|
|
||||||
"manage_roles": false,
|
|
||||||
"manage_servers": true,
|
|
||||||
"manage_tickets": true,
|
|
||||||
"manage_files": true,
|
|
||||||
"delete_users": false,
|
|
||||||
"view_all_resources": false
|
|
||||||
},
|
|
||||||
"resource_access": {
|
|
||||||
"servers": [
|
|
||||||
"test",
|
|
||||||
"nya"
|
|
||||||
],
|
|
||||||
"tickets": [],
|
|
||||||
"files": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"arkonsad": {
|
|
||||||
"username": "arkonsad",
|
|
||||||
"password": "$2b$12$z.AYkfa/MlTYFd9rLNfBmu9JHOFKUe8YdddnqCmRqAxc7vGQeo392",
|
|
||||||
"role": "user",
|
|
||||||
"servers": [
|
|
||||||
"123",
|
|
||||||
"sdfsdf"
|
|
||||||
],
|
|
||||||
"permissions": {
|
|
||||||
"manage_users": false,
|
|
||||||
"manage_roles": false,
|
|
||||||
"manage_servers": true,
|
|
||||||
"manage_tickets": true,
|
|
||||||
"manage_files": true,
|
|
||||||
"delete_users": false,
|
|
||||||
"view_all_resources": false
|
|
||||||
},
|
|
||||||
"resource_access": {
|
|
||||||
"servers": [
|
|
||||||
"123",
|
|
||||||
"sdfsdf"
|
|
||||||
],
|
|
||||||
"tickets": [],
|
|
||||||
"files": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
75
backend/users.json1
Normal file
75
backend/users.json1
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"Root": {
|
||||||
|
"username": "Root",
|
||||||
|
"password": "$2b$12$PAaomoUWn3Ip5ov.S/uYPeTIRiDMq7DbA57ahyYQnw3QHT2zuYMlG",
|
||||||
|
"role": "owner",
|
||||||
|
"servers": [],
|
||||||
|
"permissions": {
|
||||||
|
"manage_users": true,
|
||||||
|
"manage_roles": true,
|
||||||
|
"manage_servers": true,
|
||||||
|
"manage_tickets": true,
|
||||||
|
"manage_files": true,
|
||||||
|
"delete_users": true,
|
||||||
|
"view_all_resources": true
|
||||||
|
},
|
||||||
|
"resource_access": {
|
||||||
|
"servers": [],
|
||||||
|
"tickets": [],
|
||||||
|
"files": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MihailPrud": {
|
||||||
|
"username": "MihailPrud",
|
||||||
|
"password": "$2b$12$GfbQN4scE.b.mtUHofWWE.Dn1tQpT1zwLAxeICv90sHP4zGv0dc2G",
|
||||||
|
"role": "owner",
|
||||||
|
"servers": [
|
||||||
|
"test",
|
||||||
|
"nya"
|
||||||
|
],
|
||||||
|
"permissions": {
|
||||||
|
"manage_users": true,
|
||||||
|
"manage_roles": true,
|
||||||
|
"manage_servers": true,
|
||||||
|
"manage_tickets": true,
|
||||||
|
"manage_files": true,
|
||||||
|
"delete_users": true,
|
||||||
|
"view_all_resources": true
|
||||||
|
},
|
||||||
|
"resource_access": {
|
||||||
|
"servers": [
|
||||||
|
"test",
|
||||||
|
"nya"
|
||||||
|
],
|
||||||
|
"tickets": [],
|
||||||
|
"files": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"arkonsad": {
|
||||||
|
"username": "arkonsad",
|
||||||
|
"password": "$2b$12$z.AYkfa/MlTYFd9rLNfBmu9JHOFKUe8YdddnqCmRqAxc7vGQeo392",
|
||||||
|
"role": "banned",
|
||||||
|
"servers": [
|
||||||
|
"123",
|
||||||
|
"sdfsdf"
|
||||||
|
],
|
||||||
|
"permissions": {
|
||||||
|
"manage_users": false,
|
||||||
|
"manage_roles": false,
|
||||||
|
"manage_servers": false,
|
||||||
|
"manage_tickets": false,
|
||||||
|
"manage_files": false,
|
||||||
|
"delete_users": false,
|
||||||
|
"view_all_resources": false
|
||||||
|
},
|
||||||
|
"resource_access": {
|
||||||
|
"servers": [
|
||||||
|
"123",
|
||||||
|
"sdfsdf"
|
||||||
|
],
|
||||||
|
"tickets": [],
|
||||||
|
"files": []
|
||||||
|
},
|
||||||
|
"ban_reason": "Заблокирован администратором"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user