Update files
This commit is contained in:
parent
d6ed268c4a
commit
a93c95158f
|
|
@ -21,29 +21,40 @@ const OWNER_USERNAMES = new Set(config.moderationOwnerUsernames || []);
|
||||||
|
|
||||||
// Проверка доступа к модерации (только для модераторов и админов)
|
// Проверка доступа к модерации (только для модераторов и админов)
|
||||||
const requireModerationAccess = async (req, res, next) => {
|
const requireModerationAccess = async (req, res, next) => {
|
||||||
// Проверить роль пользователя
|
if (!req.user) {
|
||||||
if (!req.user || !['moderator', 'admin'].includes(req.user.role)) {
|
|
||||||
return res.status(403).json({ error: 'Недостаточно прав для модерации' });
|
return res.status(403).json({ error: 'Недостаточно прав для модерации' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Для JWT авторизации (без Telegram) - достаточно проверки роли
|
// Для JWT авторизации (без Telegram) - проверяем роль
|
||||||
if (!req.user.telegramId) {
|
if (!req.user.telegramId) {
|
||||||
|
if (!['moderator', 'admin'].includes(req.user.role)) {
|
||||||
|
return res.status(403).json({ error: 'Недостаточно прав для модерации' });
|
||||||
|
}
|
||||||
req.isModerationAdmin = true;
|
req.isModerationAdmin = true;
|
||||||
req.isOwner = req.user.role === 'admin';
|
req.isOwner = req.user.role === 'admin';
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Для Telegram авторизации - проверяем через isModerationAdmin
|
||||||
const username = normalizeUsername(req.user?.username);
|
const username = normalizeUsername(req.user?.username);
|
||||||
const telegramId = req.user?.telegramId;
|
const telegramId = req.user?.telegramId;
|
||||||
|
|
||||||
|
// Владелец или админ по роли - всегда доступ
|
||||||
if (OWNER_USERNAMES.has(username) || req.user.role === 'admin') {
|
if (OWNER_USERNAMES.has(username) || req.user.role === 'admin') {
|
||||||
req.isModerationAdmin = true;
|
req.isModerationAdmin = true;
|
||||||
req.isOwner = true;
|
req.isOwner = true;
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверить, является ли пользователь модератором через ModerationAdmin
|
||||||
const allowed = await isModerationAdmin({ telegramId, username });
|
const allowed = await isModerationAdmin({ telegramId, username });
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
|
// Если не модератор по базе, но роль moderator или admin - разрешить
|
||||||
|
if (['moderator', 'admin'].includes(req.user.role)) {
|
||||||
|
req.isModerationAdmin = true;
|
||||||
|
req.isOwner = req.user.role === 'admin';
|
||||||
|
return next();
|
||||||
|
}
|
||||||
return res.status(403).json({ error: 'Недостаточно прав для модерации' });
|
return res.status(403).json({ error: 'Недостаточно прав для модерации' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -309,8 +309,11 @@ router.post('/telegram-widget', authLimiter, async (req, res) => {
|
||||||
router.post('/telegram', authLimiter, authenticateModeration, async (req, res) => {
|
router.post('/telegram', authLimiter, authenticateModeration, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const user = req.user;
|
const user = req.user;
|
||||||
|
const { isModerationAdmin } = require('../services/moderationAdmin');
|
||||||
|
const { normalizeUsername } = require('../services/moderationAdmin');
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
if (!user || !['moderator', 'admin'].includes(user.role)) {
|
if (!user) {
|
||||||
return res.status(403).json({ error: 'Доступ запрещен' });
|
return res.status(403).json({ error: 'Доступ запрещен' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,6 +321,21 @@ router.post('/telegram', authLimiter, authenticateModeration, async (req, res) =
|
||||||
return res.status(403).json({ error: 'Аккаунт заблокирован' });
|
return res.status(403).json({ error: 'Аккаунт заблокирован' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверить доступ: роль admin/moderator ИЛИ является модератором через ModerationAdmin
|
||||||
|
const username = normalizeUsername(user.username);
|
||||||
|
const telegramId = user.telegramId;
|
||||||
|
const OWNER_USERNAMES = new Set(config.moderationOwnerUsernames || []);
|
||||||
|
|
||||||
|
const isOwner = OWNER_USERNAMES.has(username);
|
||||||
|
const isAdminByRole = ['moderator', 'admin'].includes(user.role);
|
||||||
|
const isAdminByDB = await isModerationAdmin({ telegramId, username });
|
||||||
|
|
||||||
|
if (!isOwner && !isAdminByRole && !isAdminByDB) {
|
||||||
|
return res.status(403).json({
|
||||||
|
error: 'Доступ запрещен. У вас нет прав модератора. Обратитесь к администратору.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Обновить время последней активности
|
// Обновить время последней активности
|
||||||
user.lastActiveAt = new Date();
|
user.lastActiveAt = new Date();
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🔍 Проверка состояния бэкенда модерации..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка 1: Процесс запущен ли на порту 3001
|
||||||
|
echo "1️⃣ Проверка процесса на порту 3001:"
|
||||||
|
if lsof -i :3001 > /dev/null 2>&1; then
|
||||||
|
echo " ✅ Порт 3001 занят процессом:"
|
||||||
|
lsof -i :3001 | grep LISTEN
|
||||||
|
else
|
||||||
|
echo " ❌ Порт 3001 свободен - бэкенд не запущен!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка 2: HTTP запрос к бэкенду
|
||||||
|
echo "2️⃣ Проверка доступности бэкенда:"
|
||||||
|
if curl -s http://localhost:3001/health > /dev/null 2>&1; then
|
||||||
|
echo " ✅ Бэкенд отвечает на /health:"
|
||||||
|
curl -s http://localhost:3001/health | jq . 2>/dev/null || curl -s http://localhost:3001/health
|
||||||
|
else
|
||||||
|
echo " ❌ Бэкенд недоступен по http://localhost:3001/health"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка 3: Через Nginx
|
||||||
|
echo "3️⃣ Проверка через Nginx:"
|
||||||
|
if curl -s https://moderation.nkm.guru/api/health > /dev/null 2>&1; then
|
||||||
|
echo " ✅ Nginx проксирует запросы:"
|
||||||
|
curl -s https://moderation.nkm.guru/api/health | jq . 2>/dev/null || curl -s https://moderation.nkm.guru/api/health
|
||||||
|
else
|
||||||
|
echo " ❌ Nginx не может достучаться до бэкенда"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка 4: Логи Nginx
|
||||||
|
echo "4️⃣ Последние ошибки из Nginx:"
|
||||||
|
if [ -f /var/log/nginx/moderation-error.log ]; then
|
||||||
|
echo " Последние 5 строк:"
|
||||||
|
tail -5 /var/log/nginx/moderation-error.log
|
||||||
|
else
|
||||||
|
echo " ⚠️ Файл логов не найден: /var/log/nginx/moderation-error.log"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📋 РЕШЕНИЕ:"
|
||||||
|
echo "Если бэкенд не запущен, выполните:"
|
||||||
|
echo ""
|
||||||
|
echo "cd /Users/glpshchn/Desktop/nakama/moderation/backend"
|
||||||
|
echo "NODE_ENV=production PORT=3001 MODERATION_PORT=3001 node server.js"
|
||||||
|
echo ""
|
||||||
|
echo "Или используйте PM2:"
|
||||||
|
echo "pm2 start moderation/backend/server.js --name moderation-backend --env production"
|
||||||
|
echo "pm2 save"
|
||||||
|
|
||||||
|
|
@ -68,8 +68,8 @@ services:
|
||||||
dockerfile: Dockerfile.moderation-backend
|
dockerfile: Dockerfile.moderation-backend
|
||||||
container_name: nakama-moderation-backend
|
container_name: nakama-moderation-backend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
expose:
|
ports:
|
||||||
- "3001"
|
- "127.0.0.1:3001:3001" # Проброс порта на хост для Nginx
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- PORT=3001
|
- PORT=3001
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🔧 Исправление проблемы с портом бэкенда модерации..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Остановить и удалить контейнер
|
||||||
|
echo "1️⃣ Остановка контейнера..."
|
||||||
|
docker stop nakama-moderation-backend 2>/dev/null || true
|
||||||
|
docker rm nakama-moderation-backend 2>/dev/null || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Пересобрать и перезапустить
|
||||||
|
echo "2️⃣ Пересборка и запуск контейнера с проброшенным портом..."
|
||||||
|
docker-compose up -d moderation-backend
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка
|
||||||
|
echo "3️⃣ Проверка доступности порта..."
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
if lsof -i :3001 > /dev/null 2>&1; then
|
||||||
|
echo " ✅ Порт 3001 доступен:"
|
||||||
|
lsof -i :3001 | grep LISTEN
|
||||||
|
else
|
||||||
|
echo " ⚠️ Порт 3001 еще не доступен, подождите..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка здоровья
|
||||||
|
echo "4️⃣ Проверка здоровья бэкенда..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
if curl -s http://localhost:3001/health > /dev/null 2>&1; then
|
||||||
|
echo " ✅ Бэкенд отвечает:"
|
||||||
|
curl -s http://localhost:3001/health | jq . 2>/dev/null || curl -s http://localhost:3001/health
|
||||||
|
else
|
||||||
|
echo " ⚠️ Бэкенд еще не готов, проверьте логи:"
|
||||||
|
echo " docker logs nakama-moderation-backend"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Готово! Теперь Nginx должен иметь доступ к бэкенду на порту 3001"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🔍 Проверка конфликтов в nginx конфигурации..."
|
||||||
|
|
||||||
|
# Проверить существующие конфигурации
|
||||||
|
echo "📋 Существующие конфигурации:"
|
||||||
|
ls -la /etc/nginx/sites-enabled/
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🔍 Поиск moderation.nkm.guru в конфигурациях:"
|
||||||
|
grep -r "moderation.nkm.guru" /etc/nginx/sites-enabled/ 2>/dev/null || echo "Не найдено в sites-enabled"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📝 Содержимое /etc/nginx/sites-enabled/nakama (если существует):"
|
||||||
|
if [ -f "/etc/nginx/sites-enabled/nakama" ]; then
|
||||||
|
echo "--- Начало файла nakama ---"
|
||||||
|
head -100 /etc/nginx/sites-enabled/nakama
|
||||||
|
echo "--- Конец ---"
|
||||||
|
else
|
||||||
|
echo "Файл не найден"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "⚠️ РЕШЕНИЕ:"
|
||||||
|
echo "1. Если moderation.nkm.guru уже настроен в /etc/nginx/sites-enabled/nakama:"
|
||||||
|
echo " - Удалите настройки moderation.nkm.guru из этого файла"
|
||||||
|
echo " - Или удалите весь файл если он не нужен"
|
||||||
|
echo ""
|
||||||
|
echo "2. Затем установите новую конфигурацию:"
|
||||||
|
echo " sudo cp nginx-moderation-production.conf /etc/nginx/sites-available/moderation.nkm.guru"
|
||||||
|
echo " sudo ln -sf /etc/nginx/sites-available/moderation.nkm.guru /etc/nginx/sites-enabled/"
|
||||||
|
echo " sudo nginx -t"
|
||||||
|
echo " sudo systemctl reload nginx"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Скрипт для установки конфигурации nginx для модерации
|
||||||
|
|
||||||
|
echo "🔧 Установка конфигурации Nginx для moderation.nkm.guru"
|
||||||
|
|
||||||
|
# Создать директорию если не существует
|
||||||
|
sudo mkdir -p /etc/nginx/sites-available
|
||||||
|
sudo mkdir -p /etc/nginx/sites-enabled
|
||||||
|
|
||||||
|
# Путь к файлу конфигурации
|
||||||
|
CONFIG_FILE="nginx-moderation-production.conf"
|
||||||
|
|
||||||
|
# Проверить существование файла
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
echo "❌ Ошибка: Файл $CONFIG_FILE не найден!"
|
||||||
|
echo "Убедитесь что вы в директории проекта"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Скопировать конфигурацию
|
||||||
|
echo "📋 Копирование конфигурации..."
|
||||||
|
sudo cp "$CONFIG_FILE" /etc/nginx/sites-available/moderation.nkm.guru
|
||||||
|
|
||||||
|
# Создать симлинк
|
||||||
|
echo "🔗 Создание симлинка..."
|
||||||
|
sudo ln -sf /etc/nginx/sites-available/moderation.nkm.guru /etc/nginx/sites-enabled/moderation.nkm.guru
|
||||||
|
|
||||||
|
# Проверить конфигурацию
|
||||||
|
echo "✔️ Проверка конфигурации nginx..."
|
||||||
|
if sudo nginx -t; then
|
||||||
|
echo "✅ Конфигурация корректна!"
|
||||||
|
echo "🔄 Перезагрузка nginx..."
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
echo "✅ Готово! Конфигурация применена."
|
||||||
|
else
|
||||||
|
echo "❌ Ошибка в конфигурации nginx!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
@ -48,6 +48,78 @@ EMAIL_FROM=noreply@nakama.guru
|
||||||
4. Пользователь вводит код, username и пароль
|
4. Пользователь вводит код, username и пароль
|
||||||
5. Аккаунт активируется
|
5. Аккаунт активируется
|
||||||
|
|
||||||
|
## Деплой БЕЗ Docker (локально)
|
||||||
|
|
||||||
|
### 1. Настройка переменных окружения
|
||||||
|
|
||||||
|
Добавьте в `.env` в корне проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Модерация
|
||||||
|
MODERATION_PORT=3001
|
||||||
|
MODERATION_CORS_ORIGIN=https://moderation.nkm.guru
|
||||||
|
VITE_MODERATION_API_URL=https://moderation.nkm.guru/api # ВАЖНО: обязательно HTTPS!
|
||||||
|
|
||||||
|
# Email для кодов подтверждения админа
|
||||||
|
OWNER_EMAIL=aaem9848@gmail.com
|
||||||
|
|
||||||
|
# Email настройки (выберите один вариант выше)
|
||||||
|
EMAIL_PROVIDER=aws
|
||||||
|
# ... остальные настройки email
|
||||||
|
|
||||||
|
# MongoDB (та же база что и основной бэкенд)
|
||||||
|
MONGODB_URI=mongodb://103.80.87.247:27017/nakama
|
||||||
|
|
||||||
|
# JWT (те же ключи что и основной бэкенд)
|
||||||
|
JWT_SECRET=your_jwt_secret
|
||||||
|
JWT_ACCESS_SECRET=your_access_secret
|
||||||
|
JWT_REFRESH_SECRET=your_refresh_secret
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Запуск бэкенда модерации
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/glpshchn/Desktop/nakama/moderation/backend
|
||||||
|
NODE_ENV=production PORT=3001 MODERATION_PORT=3001 node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Или с PM2 (рекомендуется):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/glpshchn/Desktop/nakama
|
||||||
|
pm2 start moderation/backend/server.js --name moderation-backend --env production -- \
|
||||||
|
NODE_ENV=production PORT=3001 MODERATION_PORT=3001
|
||||||
|
pm2 save
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Проверка работы бэкенда
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Проверка бэкенда
|
||||||
|
curl http://localhost:3001/health
|
||||||
|
|
||||||
|
# Проверка через nginx
|
||||||
|
curl https://moderation.nkm.guru/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Настройка Nginx
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Скопировать конфигурацию
|
||||||
|
sudo cp nginx-moderation-production.conf /etc/nginx/sites-available/moderation.nkm.guru
|
||||||
|
|
||||||
|
# Активировать конфигурацию
|
||||||
|
sudo ln -sf /etc/nginx/sites-available/moderation.nkm.guru /etc/nginx/sites-enabled/
|
||||||
|
|
||||||
|
# Проверить конфигурацию
|
||||||
|
sudo nginx -t
|
||||||
|
|
||||||
|
# Перезагрузить nginx
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ ВАЖНО:** Убедитесь, что в `/etc/nginx/sites-enabled/nakama` нет дублирующих настроек для `moderation.nkm.guru`. Если есть - удалите их, иначе будет конфликт.
|
||||||
|
|
||||||
## Деплой с Docker
|
## Деплой с Docker
|
||||||
|
|
||||||
### 1. Настройка переменных окружения
|
### 1. Настройка переменных окружения
|
||||||
|
|
@ -126,10 +198,56 @@ docker-compose restart nginx-moderation
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
### 502 Bad Gateway
|
||||||
|
|
||||||
|
Это означает, что Nginx не может подключиться к бэкенду. Проверьте:
|
||||||
|
|
||||||
|
1. **Бэкенд запущен?**
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3001/health
|
||||||
|
# Должен вернуть: {"status":"ok","service":"moderation",...}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Порт 3001 свободен?**
|
||||||
|
```bash
|
||||||
|
lsof -i :3001
|
||||||
|
# Должен показать процесс Node.js
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Логи Nginx:**
|
||||||
|
```bash
|
||||||
|
sudo tail -f /var/log/nginx/moderation-error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Запустите бэкенд:**
|
||||||
|
```bash
|
||||||
|
cd /Users/glpshchn/Desktop/nakama/moderation/backend
|
||||||
|
NODE_ENV=production PORT=3001 MODERATION_PORT=3001 node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### Конфликт конфигурации Nginx
|
||||||
|
|
||||||
|
Если видите ошибки типа "conflicting server name" или "protocol options redefined":
|
||||||
|
|
||||||
|
1. Проверьте дубликаты в `/etc/nginx/sites-enabled/`:
|
||||||
|
```bash
|
||||||
|
grep -r "moderation.nkm.guru" /etc/nginx/sites-enabled/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Удалите дублирующие настройки из `/etc/nginx/sites-enabled/nakama` (если есть)
|
||||||
|
|
||||||
|
3. Перезагрузите nginx:
|
||||||
|
```bash
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
### Email не отправляется
|
### Email не отправляется
|
||||||
|
|
||||||
1. Проверьте настройки EMAIL_PROVIDER в .env
|
1. Проверьте настройки EMAIL_PROVIDER в .env
|
||||||
2. Проверьте логи: `docker-compose logs moderation-backend`
|
2. Проверьте логи бэкенда:
|
||||||
|
- Если через PM2: `pm2 logs moderation-backend`
|
||||||
|
- Если напрямую: логи в консоли
|
||||||
3. Убедитесь что credentials правильные
|
3. Убедитесь что credentials правильные
|
||||||
|
|
||||||
### Не работает авторизация
|
### Не работает авторизация
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@
|
||||||
<title>Nakama Moderation</title>
|
<title>Nakama Moderation</title>
|
||||||
<!-- Telegram Web App SDK -->
|
<!-- Telegram Web App SDK -->
|
||||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||||
<!-- Telegram Login Widget SDK -->
|
|
||||||
<script async src="https://telegram.org/js/telegram-widget.js?22" data-telegram-login="NakamaSpaceBot" data-size="large" data-request-access="write"></script>
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
||||||
|
|
@ -154,12 +154,18 @@ export default function App() {
|
||||||
const result = await loginTelegram();
|
const result = await loginTelegram();
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
setUser(result.user);
|
if (result && result.user) {
|
||||||
setError(null);
|
setUser(result.user);
|
||||||
|
setError(null);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Telegram авторизация не удалась:', err);
|
||||||
|
// В MiniApp при ошибке показываем ошибку, а не форму входа
|
||||||
|
setError(err?.response?.data?.error || 'Ошибка авторизации. Убедитесь, что у вас есть права модератора.');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
} catch (err) {
|
|
||||||
console.warn('Telegram авторизация не удалась, пробуем JWT:', err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +217,7 @@ export default function App() {
|
||||||
const showLoginForm = error === 'login_required' || (!user && !loading);
|
const showLoginForm = error === 'login_required' || (!user && !loading);
|
||||||
|
|
||||||
// Инициализировать виджет только если нет WebApp initData и показана форма входа
|
// Инициализировать виджет только если нет WebApp initData и показана форма входа
|
||||||
if (!telegramApp?.initData && showLoginForm) {
|
if (!telegramApp?.initData && showLoginForm && telegramWidgetRef.current) {
|
||||||
// Глобальная функция для обработки авторизации через виджет
|
// Глобальная функция для обработки авторизации через виджет
|
||||||
window.onTelegramAuth = async (userData) => {
|
window.onTelegramAuth = async (userData) => {
|
||||||
console.log('Telegram Login Widget данные:', userData);
|
console.log('Telegram Login Widget данные:', userData);
|
||||||
|
|
@ -256,14 +262,21 @@ export default function App() {
|
||||||
const initWidget = () => {
|
const initWidget = () => {
|
||||||
// Проверить не загружен ли уже виджет
|
// Проверить не загружен ли уже виджет
|
||||||
if (document.querySelector('script[src*="telegram-widget"]')) {
|
if (document.querySelector('script[src*="telegram-widget"]')) {
|
||||||
|
console.log('[Telegram Widget] Виджет уже загружен');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgetContainer = telegramWidgetRef.current;
|
const widgetContainer = telegramWidgetRef.current;
|
||||||
if (!widgetContainer) {
|
if (!widgetContainer) {
|
||||||
|
console.warn('[Telegram Widget] Контейнер не найден');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[Telegram Widget] Инициализация виджета...');
|
||||||
|
|
||||||
|
// Очистить контейнер перед добавлением скрипта
|
||||||
|
widgetContainer.innerHTML = '';
|
||||||
|
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.src = 'https://telegram.org/js/telegram-widget.js?22';
|
script.src = 'https://telegram.org/js/telegram-widget.js?22';
|
||||||
|
|
@ -271,12 +284,21 @@ export default function App() {
|
||||||
script.setAttribute('data-size', 'large');
|
script.setAttribute('data-size', 'large');
|
||||||
script.setAttribute('data-request-access', 'write');
|
script.setAttribute('data-request-access', 'write');
|
||||||
script.setAttribute('data-onauth', 'onTelegramAuth');
|
script.setAttribute('data-onauth', 'onTelegramAuth');
|
||||||
|
script.setAttribute('data-radius', '10');
|
||||||
|
|
||||||
|
script.onload = () => {
|
||||||
|
console.log('[Telegram Widget] Скрипт загружен');
|
||||||
|
};
|
||||||
|
|
||||||
|
script.onerror = () => {
|
||||||
|
console.error('[Telegram Widget] Ошибка загрузки скрипта');
|
||||||
|
};
|
||||||
|
|
||||||
widgetContainer.appendChild(script);
|
widgetContainer.appendChild(script);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Подождать немного чтобы контейнер был готов
|
// Подождать немного чтобы контейнер был готов
|
||||||
const timer = setTimeout(initWidget, 500);
|
const timer = setTimeout(initWidget, 100);
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
if (window.onTelegramAuth) {
|
if (window.onTelegramAuth) {
|
||||||
|
|
@ -1305,43 +1327,20 @@ export default function App() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Показать форму входа
|
// Показать форму входа ТОЛЬКО если это НЕ MiniApp
|
||||||
if (error === 'login_required' || (!user && !loading)) {
|
const telegramApp = window.Telegram?.WebApp;
|
||||||
const telegramApp = window.Telegram?.WebApp;
|
const isMiniApp = telegramApp && telegramApp.initData;
|
||||||
const canUseTelegram = telegramApp && telegramApp.initData;
|
|
||||||
|
|
||||||
|
if (error === 'login_required' || (!user && !loading && !isMiniApp)) {
|
||||||
return (
|
return (
|
||||||
<div className="fullscreen-center">
|
<div className="fullscreen-center">
|
||||||
<div className="login-card">
|
<div className="login-card">
|
||||||
<h1 style={{ marginTop: 0, marginBottom: '24px' }}>Вход в модерацию</h1>
|
<h1 style={{ marginTop: 0, marginBottom: '24px' }}>Вход в модерацию</h1>
|
||||||
|
|
||||||
{/* Telegram авторизация */}
|
{/* Telegram авторизация в MiniApp - не показываем, авторизация автоматическая */}
|
||||||
{canUseTelegram && (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
className="btn primary"
|
|
||||||
onClick={handleTelegramLogin}
|
|
||||||
disabled={authLoading}
|
|
||||||
style={{ width: '100%', justifyContent: 'center', marginBottom: '16px' }}
|
|
||||||
>
|
|
||||||
{authLoading ? <Loader2 className="spin" size={18} /> : '🔐 Войти через Telegram'}
|
|
||||||
</button>
|
|
||||||
<div style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
marginBottom: '24px',
|
|
||||||
padding: '16px',
|
|
||||||
background: 'rgba(255, 255, 255, 0.05)',
|
|
||||||
borderRadius: '8px'
|
|
||||||
}}>
|
|
||||||
<p style={{ margin: 0, fontSize: '14px', color: 'var(--text-secondary)' }}>
|
|
||||||
или
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Telegram Login Widget для обычного браузера */}
|
{/* Telegram Login Widget для обычного браузера */}
|
||||||
{!canUseTelegram && (
|
{!isMiniApp && (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
id="telegram-login-widget"
|
id="telegram-login-widget"
|
||||||
|
|
@ -1560,16 +1559,21 @@ export default function App() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Показать ошибку (особенно важно для MiniApp)
|
||||||
if (error && error !== 'login_required') {
|
if (error && error !== 'login_required') {
|
||||||
|
const telegramApp = window.Telegram?.WebApp;
|
||||||
|
const isMiniApp = telegramApp && telegramApp.initData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fullscreen-center">
|
<div className="fullscreen-center">
|
||||||
<ShieldCheck size={48} />
|
<ShieldCheck size={48} />
|
||||||
<p>{error}</p>
|
<p style={{ marginTop: '16px', textAlign: 'center', maxWidth: '400px' }}>{error}</p>
|
||||||
{error.includes('доступ') && (
|
{!isMiniApp && error.includes('доступ') && (
|
||||||
<button
|
<button
|
||||||
className="btn"
|
className="btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
localStorage.removeItem('moderation_token');
|
localStorage.removeItem('moderation_token');
|
||||||
|
localStorage.removeItem('moderation_jwt_token');
|
||||||
setError('login_required');
|
setError('login_required');
|
||||||
}}
|
}}
|
||||||
style={{ marginTop: '16px' }}
|
style={{ marginTop: '16px' }}
|
||||||
|
|
@ -1577,6 +1581,27 @@ export default function App() {
|
||||||
Войти заново
|
Войти заново
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{isMiniApp && (
|
||||||
|
<button
|
||||||
|
className="btn"
|
||||||
|
onClick={async () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const result = await loginTelegram();
|
||||||
|
setUser(result.user);
|
||||||
|
setError(null);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err?.response?.data?.error || 'Ошибка авторизации');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ marginTop: '16px' }}
|
||||||
|
>
|
||||||
|
Попробовать снова
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Скрипт для запуска бэкенда модерации
|
||||||
|
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
echo "🚀 Запуск бэкенда модерации..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Проверка существования .env
|
||||||
|
if [ ! -f ".env" ]; then
|
||||||
|
echo "⚠️ Файл .env не найден в корне проекта!"
|
||||||
|
echo " Создайте его на основе ENV_EXAMPLE.txt"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Проверка занятости порта
|
||||||
|
if lsof -i :3001 > /dev/null 2>&1; then
|
||||||
|
echo "⚠️ Порт 3001 уже занят!"
|
||||||
|
echo " Остановите существующий процесс или измените порт"
|
||||||
|
lsof -i :3001
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Проверка установки зависимостей
|
||||||
|
if [ ! -d "node_modules" ]; then
|
||||||
|
echo "📦 Установка зависимостей..."
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Запуск сервера модерации на порту 3001..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Запуск с переменными окружения
|
||||||
|
cd moderation/backend
|
||||||
|
NODE_ENV=production \
|
||||||
|
PORT=3001 \
|
||||||
|
MODERATION_PORT=3001 \
|
||||||
|
node server.js
|
||||||
|
|
||||||
Loading…
Reference in New Issue