From 8092d25c0cf90920dff91f3302a047d64f4ca876 Mon Sep 17 00:00:00 2001 From: glpshchn <464976@niuitmo.ru> Date: Mon, 1 Dec 2025 04:02:46 +0300 Subject: [PATCH] Update files --- DEPLOY.md | 177 +++++++++++++++++++++++++++++++++++++ backend/middleware/auth.js | 118 +++++++++++++++---------- fix-docker-error.sh | 37 ++++++++ 3 files changed, 284 insertions(+), 48 deletions(-) create mode 100644 DEPLOY.md create mode 100644 fix-docker-error.sh diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..f6abf38 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,177 @@ +# 🚀 Инструкция по обновлению сервера + +## Вариант 1: PM2 (рекомендуется) + +### 1. Подключитесь к серверу +```bash +ssh user@your-server +cd /var/www/nakama # или путь к вашему проекту +``` + +### 2. Обновите код +```bash +# Если используете Git +git pull origin main + +# Или загрузите файлы вручную через SFTP/SCP +``` + +### 3. Установите зависимости (если нужно) +```bash +# Backend зависимости +npm install --production + +# Frontend зависимости и сборка +cd frontend +npm install +npm run build +cd .. +``` + +### 4. Перезапустите backend +```bash +pm2 restart nakama-backend +``` + +### 5. Проверьте статус +```bash +pm2 status +pm2 logs nakama-backend --lines 50 +``` + +### Или используйте готовый скрипт: +```bash +chmod +x update-server.sh +./update-server.sh +``` + +--- + +## Вариант 2: Docker + +### 1. Подключитесь к серверу +```bash +ssh user@your-server +cd /path/to/nakama +``` + +### 2. Обновите код +```bash +# Если используете Git +git pull origin main + +# Или загрузите файлы вручную +``` + +### 3. Пересоберите и перезапустите контейнеры +```bash +# Пересобрать только backend (если изменился только backend) +docker-compose build backend +docker-compose up -d backend + +# Или пересобрать всё +docker-compose build +docker-compose up -d +``` + +### 4. Проверьте статус +```bash +docker-compose ps +docker-compose logs -f backend +``` + +--- + +## Быстрое обновление (только backend) + +Если изменился только backend код: + +### PM2: +```bash +cd /var/www/nakama +git pull +pm2 restart nakama-backend +``` + +### Docker: +```bash +cd /path/to/nakama +git pull +docker-compose build backend +docker-compose up -d backend +``` + +--- + +## Проверка после обновления + +1. **Проверьте логи:** + ```bash + # PM2 + pm2 logs nakama-backend --lines 50 + + # Docker + docker-compose logs backend --tail 50 + ``` + +2. **Проверьте здоровье сервера:** + ```bash + curl http://localhost:3000/health + ``` + +3. **Проверьте работу приложения:** + - Откройте приложение в браузере + - Попробуйте авторизоваться + - Проверьте, что ники и аватарки отображаются + +--- + +## Что изменилось в этом обновлении + +✅ **Отключено автообновление аватарок** - больше не будет автоматического обновления всех аватарок каждый день + +✅ **Улучшено обновление данных при авторизации** - при каждом перезаходе пользователя система проверяет и подтягивает отсутствующие данные (username, firstName, lastName, photoUrl) из Telegram + +✅ **Добавлены fallback значения** - если данные отсутствуют, отображаются значения по умолчанию вместо пустых полей + +--- + +## Откат изменений (если что-то пошло не так) + +### PM2: +```bash +cd /var/www/nakama +git checkout HEAD~1 # или конкретный коммит +pm2 restart nakama-backend +``` + +### Docker: +```bash +cd /path/to/nakama +git checkout HEAD~1 +docker-compose build backend +docker-compose up -d backend +``` + +--- + +## Полезные команды + +### PM2: +```bash +pm2 list # Список процессов +pm2 restart nakama-backend # Перезапуск +pm2 stop nakama-backend # Остановка +pm2 logs nakama-backend # Логи +pm2 monit # Мониторинг +``` + +### Docker: +```bash +docker-compose ps # Статус контейнеров +docker-compose logs -f # Логи всех сервисов +docker-compose restart backend # Перезапуск backend +docker-compose down # Остановка всех контейнеров +docker-compose up -d # Запуск всех контейнеров +``` + diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index 54de65f..05149a3 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -48,40 +48,54 @@ const ensureUserSettings = async (user) => { } }; +// Нормализовать данные пользователя из Telegram (поддержка camelCase и snake_case) +const normalizeTelegramUser = (telegramUser) => { + return { + id: telegramUser.id, + username: telegramUser.username || telegramUser.userName, + firstName: telegramUser.firstName || telegramUser.first_name || '', + lastName: telegramUser.lastName || telegramUser.last_name || '', + photoUrl: telegramUser.photoUrl || telegramUser.photo_url || null + }; +}; + // Подтянуть отсутствующие данные пользователя из Telegram const ensureUserData = async (user, telegramUser) => { if (!user || !telegramUser) return; + // Нормализовать данные (поддержка camelCase и snake_case) + const normalized = normalizeTelegramUser(telegramUser); + let updated = false; // Обновить username, если отсутствует или пустой if (!user.username || user.username.trim() === '') { - if (telegramUser.username) { - user.username = telegramUser.username; + if (normalized.username) { + user.username = normalized.username; updated = true; - } else if (telegramUser.first_name) { - user.username = telegramUser.first_name; + } else if (normalized.firstName) { + user.username = normalized.firstName; updated = true; } } // Обновить firstName, если отсутствует - if (!user.firstName && telegramUser.first_name) { - user.firstName = telegramUser.first_name; + if (!user.firstName && normalized.firstName) { + user.firstName = normalized.firstName; updated = true; } // Обновить lastName, если отсутствует if (user.lastName === undefined || user.lastName === null) { - user.lastName = telegramUser.last_name || ''; + user.lastName = normalized.lastName; updated = true; } // Обновить аватарку, если отсутствует if (!user.photoUrl) { - // Сначала проверить photo_url из initData - if (telegramUser.photo_url) { - user.photoUrl = telegramUser.photo_url; + // Сначала проверить photoUrl из initData + if (normalized.photoUrl) { + user.photoUrl = normalized.photoUrl; updated = true; } else { // Если нет в initData, попробовать получить через Bot API @@ -145,37 +159,40 @@ const authenticate = async (req, res, next) => { return res.status(401).json({ error: 'Неверный ID пользователя' }); } - let user = await User.findOne({ telegramId: telegramUser.id.toString() }); + // Нормализовать данные пользователя (библиотека возвращает camelCase, но может быть и snake_case) + const normalizedUser = normalizeTelegramUser(telegramUser); + + let user = await User.findOne({ telegramId: normalizedUser.id.toString() }); if (!user) { user = new User({ - telegramId: telegramUser.id.toString(), - username: telegramUser.username || telegramUser.first_name || 'user', - firstName: telegramUser.first_name || '', - lastName: telegramUser.last_name || '', - photoUrl: telegramUser.photo_url || null + telegramId: normalizedUser.id.toString(), + username: normalizedUser.username || normalizedUser.firstName || 'user', + firstName: normalizedUser.firstName, + lastName: normalizedUser.lastName, + photoUrl: normalizedUser.photoUrl }); await user.save(); } else { // Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями - if (telegramUser.username) { - user.username = telegramUser.username; - } else if (!user.username && telegramUser.first_name) { - // Если username пустой, использовать first_name как fallback - user.username = telegramUser.first_name; + if (normalizedUser.username) { + user.username = normalizedUser.username; + } else if (!user.username && normalizedUser.firstName) { + // Если username пустой, использовать firstName как fallback + user.username = normalizedUser.firstName; } - if (telegramUser.first_name) { - user.firstName = telegramUser.first_name; + if (normalizedUser.firstName) { + user.firstName = normalizedUser.firstName; } - if (telegramUser.last_name !== undefined) { - user.lastName = telegramUser.last_name || ''; + if (normalizedUser.lastName !== undefined) { + user.lastName = normalizedUser.lastName; } // Обновлять аватарку только если есть новая - if (telegramUser.photo_url) { - user.photoUrl = telegramUser.photo_url; + if (normalizedUser.photoUrl) { + user.photoUrl = normalizedUser.photoUrl; } await user.save(); @@ -185,11 +202,13 @@ const authenticate = async (req, res, next) => { return res.status(403).json({ error: 'Пользователь заблокирован' }); } + // Подтянуть отсутствующие данные из Telegram (используем нормализованные данные) + await ensureUserData(user, normalizedUser); await ensureUserSettings(user); await touchUserActivity(user); req.user = user; - req.telegramUser = telegramUser; + req.telegramUser = normalizedUser; next(); } catch (error) { console.error('❌ Ошибка авторизации:', error); @@ -254,37 +273,40 @@ const authenticateModeration = async (req, res, next) => { return res.status(401).json({ error: 'Неверный ID пользователя' }); } - let user = await User.findOne({ telegramId: telegramUser.id.toString() }); + // Нормализовать данные пользователя (библиотека возвращает camelCase, но может быть и snake_case) + const normalizedUser = normalizeTelegramUser(telegramUser); + + let user = await User.findOne({ telegramId: normalizedUser.id.toString() }); if (!user) { user = new User({ - telegramId: telegramUser.id.toString(), - username: telegramUser.username || telegramUser.first_name || 'user', - firstName: telegramUser.first_name || '', - lastName: telegramUser.last_name || '', - photoUrl: telegramUser.photo_url || null + telegramId: normalizedUser.id.toString(), + username: normalizedUser.username || normalizedUser.firstName || 'user', + firstName: normalizedUser.firstName, + lastName: normalizedUser.lastName, + photoUrl: normalizedUser.photoUrl }); await user.save(); } else { // Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями - if (telegramUser.username) { - user.username = telegramUser.username; - } else if (!user.username && telegramUser.first_name) { - // Если username пустой, использовать first_name как fallback - user.username = telegramUser.first_name; + if (normalizedUser.username) { + user.username = normalizedUser.username; + } else if (!user.username && normalizedUser.firstName) { + // Если username пустой, использовать firstName как fallback + user.username = normalizedUser.firstName; } - if (telegramUser.first_name) { - user.firstName = telegramUser.first_name; + if (normalizedUser.firstName) { + user.firstName = normalizedUser.firstName; } - if (telegramUser.last_name !== undefined) { - user.lastName = telegramUser.last_name || ''; + if (normalizedUser.lastName !== undefined) { + user.lastName = normalizedUser.lastName; } // Обновлять аватарку только если есть новая - if (telegramUser.photo_url) { - user.photoUrl = telegramUser.photo_url; + if (normalizedUser.photoUrl) { + user.photoUrl = normalizedUser.photoUrl; } await user.save(); @@ -294,13 +316,13 @@ const authenticateModeration = async (req, res, next) => { return res.status(403).json({ error: 'Пользователь заблокирован' }); } - // Подтянуть отсутствующие данные из Telegram - await ensureUserData(user, telegramUser); + // Подтянуть отсутствующие данные из Telegram (используем нормализованные данные) + await ensureUserData(user, normalizedUser); await ensureUserSettings(user); await touchUserActivity(user); req.user = user; - req.telegramUser = telegramUser; + req.telegramUser = normalizedUser; next(); } catch (error) { console.error('❌ Ошибка авторизации модерации:', error); diff --git a/fix-docker-error.sh b/fix-docker-error.sh new file mode 100644 index 0000000..d5f3955 --- /dev/null +++ b/fix-docker-error.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Скрипт для исправления ошибки ContainerConfig в Docker + +echo "🔧 Исправление ошибки Docker ContainerConfig..." + +# 1. Остановить и удалить проблемный контейнер +echo "📦 Остановка и удаление старого контейнера..." +docker-compose stop backend +docker-compose rm -f backend + +# 2. Удалить старый образ backend (опционально, если нужно полное пересоздание) +echo "🗑️ Удаление старого образа backend..." +docker rmi nakama-backend 2>/dev/null || echo "Образ не найден, пропускаем" + +# 3. Очистить кэш Docker (опционально, если проблема сохраняется) +# docker system prune -f + +# 4. Пересобрать образ +echo "🔨 Пересборка образа backend..." +docker-compose build --no-cache backend + +# 5. Запустить контейнер +echo "🚀 Запуск контейнера..." +docker-compose up -d backend + +# 6. Проверить статус +echo "✅ Проверка статуса..." +docker-compose ps backend +docker-compose logs backend --tail 20 + +echo "" +echo "✅ Готово! Если проблема сохраняется, попробуйте:" +echo " docker-compose down" +echo " docker-compose build --no-cache" +echo " docker-compose up -d" +