diff --git a/VIEW_USER_PROFILES.md b/VIEW_USER_PROFILES.md
new file mode 100644
index 0000000..0ff7532
--- /dev/null
+++ b/VIEW_USER_PROFILES.md
@@ -0,0 +1,187 @@
+# 👁️ Просмотр профилей пользователей
+
+## Что добавлено
+
+### Возможность просмотра профилей для админов и тех. поддержки
+Администраторы и сотрудники технической поддержки теперь могут просматривать личные кабинеты других пользователей, нажав на их логин в списке пользователей.
+
+## 🎯 Как использовать
+
+### Просмотр профиля пользователя
+1. Войдите как администратор или тех. поддержка
+2. Нажмите кнопку "Пользователи" в header
+3. Найдите нужного пользователя в списке
+4. **Нажмите на логин пользователя** (он теперь кликабельный и подсвечивается при наведении)
+5. Откроется личный кабинет этого пользователя
+
+### Что можно увидеть
+- ✅ Имя пользователя
+- ✅ Роль пользователя
+- ✅ Статистику по серверам (всего, мои, доступные)
+- ✅ Список серверов пользователя
+- ✅ Статистику по тикетам (всего, по статусам)
+
+### Что нельзя сделать
+- ❌ Изменить имя пользователя (вкладка скрыта)
+- ❌ Изменить пароль пользователя (вкладка скрыта)
+- ❌ Редактировать профиль другого пользователя
+
+## 🎨 Визуальные изменения
+
+### В списке пользователей (Users.jsx)
+- **Логин пользователя** теперь кликабельный
+- При наведении логин подсвечивается синим цветом
+- Курсор меняется на pointer (указатель)
+- Подсказка "Просмотреть профиль" при наведении
+
+### В личном кабинете (Profile.jsx)
+- **Заголовок**: "Профиль пользователя: [username]" (вместо "Личный кабинет")
+- **Подзаголовок**: "Просмотр профиля другого пользователя"
+- **Вкладки**: скрыты вкладки "Имя пользователя" и "Пароль"
+- **Только вкладка "Обзор"**: показывается статистика пользователя
+
+## 📋 Технические детали
+
+### Backend (main.py)
+
+#### Новый endpoint
+```python
+@app.get("/api/profile/stats/{username}")
+async def get_user_profile_stats(username: str, user: dict = Depends(get_current_user)):
+ """Получить статистику профиля другого пользователя"""
+ # Проверка прав доступа
+ if user["role"] not in ["admin", "support"]:
+ raise HTTPException(403, "Недостаточно прав")
+
+ # Возвращает статистику указанного пользователя
+```
+
+#### Проверка прав
+- Только администраторы и тех. поддержка могут просматривать чужие профили
+- Обычные пользователи получат ошибку 403
+
+### Frontend
+
+#### App.jsx
+```javascript
+const [viewingUsername, setViewingUsername] = useState(null);
+
+const handleViewProfile = (username) => {
+ setViewingUsername(username);
+ setShowProfile(true);
+ setShowUsers(false);
+};
+```
+
+#### Users.jsx
+```javascript
+
+```
+
+#### Profile.jsx
+```javascript
+const isViewingOther = viewingUsername && viewingUsername !== user?.username;
+
+const loadStats = async () => {
+ const endpoint = isViewingOther
+ ? `${API_URL}/api/profile/stats/${viewingUsername}`
+ : `${API_URL}/api/profile/stats`;
+ // ...
+};
+```
+
+## 🔐 Безопасность
+
+### Проверка прав на уровне API
+- Endpoint `/api/profile/stats/{username}` проверяет роль пользователя
+- Только `admin` и `support` могут получить доступ
+- Обычные пользователи получат ошибку 403
+
+### Защита на уровне UI
+- Вкладки изменения имени и пароля скрыты при просмотре чужого профиля
+- Невозможно редактировать данные другого пользователя
+- Только просмотр статистики
+
+## 📊 Доступные роли
+
+### Кто может просматривать чужие профили
+1. **Администратор** (admin) - ✅ Может просматривать все профили
+2. **Тех. поддержка** (support) - ✅ Может просматривать все профили
+3. **Пользователь** (user) - ❌ Не может просматривать чужие профили
+4. **Забанен** (banned) - ❌ Не имеет доступа к панели
+
+## ✅ Примеры использования
+
+### Сценарий 1: Проверка активности пользователя
+1. Админ хочет проверить, сколько серверов у пользователя
+2. Открывает "Пользователи"
+3. Нажимает на логин пользователя
+4. Видит статистику: 3 сервера, 5 тикетов
+
+### Сценарий 2: Помощь пользователю
+1. Тех. поддержка получила тикет от пользователя
+2. Хочет посмотреть его серверы для диагностики
+3. Открывает "Пользователи"
+4. Нажимает на логин пользователя
+5. Видит список серверов и их названия
+
+### Сценарий 3: Модерация
+1. Админ хочет проверить активность пользователя перед баном
+2. Открывает профиль пользователя
+3. Видит статистику по тикетам и серверам
+4. Принимает решение о блокировке
+
+## 🎯 Возврат к списку пользователей
+
+### Из профиля пользователя
+1. Нажмите кнопку "Серверы" в header
+2. Вы вернётесь к главной странице
+3. Снова откройте "Пользователи" для просмотра других профилей
+
+### Или откройте свой профиль
+1. Нажмите кнопку "Личный кабинет" в header
+2. Откроется ваш собственный профиль
+3. Будут доступны все вкладки (Обзор, Имя пользователя, Пароль)
+
+## ⚠️ Важные замечания
+
+### Ограничения
+- Нельзя редактировать чужие профили
+- Нельзя изменить имя или пароль другого пользователя
+- Только просмотр статистики
+
+### Рекомендации
+- Используйте эту функцию для помощи пользователям
+- Не злоупотребляйте просмотром чужих профилей
+- Соблюдайте конфиденциальность данных пользователей
+
+## ✅ Готово!
+
+Функция просмотра профилей пользователей полностью интегрирована в MC Panel. Администраторы и тех. поддержка могут легко просматривать информацию о пользователях для помощи и модерации.
+
+### Тестирование
+
+1. **Войдите как администратор**
+ - Логин: none
+ - Пароль: none
+
+2. **Создайте тестового пользователя**
+ - Зарегистрируйте нового пользователя
+ - Создайте несколько серверов от его имени
+
+3. **Просмотрите его профиль**
+ - Откройте "Пользователи"
+ - Нажмите на логин тестового пользователя
+ - Увидите его статистику
+
+4. **Вернитесь к своему профилю**
+ - Нажмите "Личный кабинет"
+ - Откроется ваш профиль со всеми вкладками
+
+**Удобного использования! 👁️**
diff --git a/backend/main.py b/backend/main.py
index 820b082..48f5d29 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -404,6 +404,60 @@ async def get_profile_stats(user: dict = Depends(get_current_user)):
"total_servers": len(owned_servers) + len(accessible_servers)
}
+@app.get("/api/profile/stats/{username}")
+async def get_user_profile_stats(username: str, user: dict = Depends(get_current_user)):
+ """Получить статистику профиля другого пользователя (только для админов и тех. поддержки)"""
+ # Проверка прав доступа
+ if user["role"] not in ["admin", "support"]:
+ raise HTTPException(403, "Недостаточно прав для просмотра профилей других пользователей")
+
+ users = load_users()
+
+ # Проверка существования пользователя
+ if username not in users:
+ raise HTTPException(404, "Пользователь не найден")
+
+ target_user = users[username]
+
+ # Подсчитываем серверы пользователя
+ owned_servers = []
+ accessible_servers = []
+
+ for server_dir in SERVERS_DIR.iterdir():
+ if server_dir.is_dir():
+ config = load_server_config(server_dir.name)
+ if config.get("owner") == username:
+ owned_servers.append({
+ "name": server_dir.name,
+ "displayName": config.get("displayName", server_dir.name)
+ })
+ elif username in target_user.get("servers", []) or target_user["role"] == "admin":
+ accessible_servers.append({
+ "name": server_dir.name,
+ "displayName": config.get("displayName", server_dir.name)
+ })
+
+ # Подсчитываем тикеты
+ tickets = load_tickets()
+ user_tickets = [t for t in tickets.values() if t["author"] == username]
+
+ tickets_stats = {
+ "total": len(user_tickets),
+ "pending": len([t for t in user_tickets if t["status"] == "pending"]),
+ "in_progress": len([t for t in user_tickets if t["status"] == "in_progress"]),
+ "closed": len([t for t in user_tickets if t["status"] == "closed"])
+ }
+
+ return {
+ "username": username,
+ "role": target_user["role"],
+ "owned_servers": owned_servers,
+ "accessible_servers": accessible_servers,
+ "tickets": tickets_stats,
+ "total_servers": len(owned_servers) + len(accessible_servers),
+ "is_viewing_other": True # Флаг что это чужой профиль
+ }
+
# API для серверов
@app.get("/api/servers")
async def get_servers(user: dict = Depends(get_current_user)):
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 25ff32f..2179ab2 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -25,6 +25,7 @@ function App() {
const [showUsers, setShowUsers] = useState(false);
const [showTickets, setShowTickets] = useState(false);
const [showProfile, setShowProfile] = useState(false);
+ const [viewingUsername, setViewingUsername] = useState(null);
const [connectionError, setConnectionError] = useState(false);
const [theme, setTheme] = useState(localStorage.getItem('theme') || 'dark');
const [sidebarOpen, setSidebarOpen] = useState(true);
@@ -118,6 +119,12 @@ function App() {
loadServers();
};
+ const handleViewProfile = (username) => {
+ setViewingUsername(username);
+ setShowProfile(true);
+ setShowUsers(false);
+ };
+
const startServer = async (serverName) => {
try {
const response = await axios.post(
@@ -201,7 +208,7 @@ function App() {
-
+
);
}
@@ -284,7 +291,10 @@ function App() {