Update files

This commit is contained in:
glpshchn 2025-12-01 04:02:46 +03:00
parent ed85d8f6db
commit 8092d25c0c
3 changed files with 284 additions and 48 deletions

177
DEPLOY.md Normal file
View File

@ -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 # Запуск всех контейнеров
```

View File

@ -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 // Подтянуть отсутствующие данные пользователя из Telegram
const ensureUserData = async (user, telegramUser) => { const ensureUserData = async (user, telegramUser) => {
if (!user || !telegramUser) return; if (!user || !telegramUser) return;
// Нормализовать данные (поддержка camelCase и snake_case)
const normalized = normalizeTelegramUser(telegramUser);
let updated = false; let updated = false;
// Обновить username, если отсутствует или пустой // Обновить username, если отсутствует или пустой
if (!user.username || user.username.trim() === '') { if (!user.username || user.username.trim() === '') {
if (telegramUser.username) { if (normalized.username) {
user.username = telegramUser.username; user.username = normalized.username;
updated = true; updated = true;
} else if (telegramUser.first_name) { } else if (normalized.firstName) {
user.username = telegramUser.first_name; user.username = normalized.firstName;
updated = true; updated = true;
} }
} }
// Обновить firstName, если отсутствует // Обновить firstName, если отсутствует
if (!user.firstName && telegramUser.first_name) { if (!user.firstName && normalized.firstName) {
user.firstName = telegramUser.first_name; user.firstName = normalized.firstName;
updated = true; updated = true;
} }
// Обновить lastName, если отсутствует // Обновить lastName, если отсутствует
if (user.lastName === undefined || user.lastName === null) { if (user.lastName === undefined || user.lastName === null) {
user.lastName = telegramUser.last_name || ''; user.lastName = normalized.lastName;
updated = true; updated = true;
} }
// Обновить аватарку, если отсутствует // Обновить аватарку, если отсутствует
if (!user.photoUrl) { if (!user.photoUrl) {
// Сначала проверить photo_url из initData // Сначала проверить photoUrl из initData
if (telegramUser.photo_url) { if (normalized.photoUrl) {
user.photoUrl = telegramUser.photo_url; user.photoUrl = normalized.photoUrl;
updated = true; updated = true;
} else { } else {
// Если нет в initData, попробовать получить через Bot API // Если нет в initData, попробовать получить через Bot API
@ -145,37 +159,40 @@ const authenticate = async (req, res, next) => {
return res.status(401).json({ error: 'Неверный ID пользователя' }); 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) { if (!user) {
user = new User({ user = new User({
telegramId: telegramUser.id.toString(), telegramId: normalizedUser.id.toString(),
username: telegramUser.username || telegramUser.first_name || 'user', username: normalizedUser.username || normalizedUser.firstName || 'user',
firstName: telegramUser.first_name || '', firstName: normalizedUser.firstName,
lastName: telegramUser.last_name || '', lastName: normalizedUser.lastName,
photoUrl: telegramUser.photo_url || null photoUrl: normalizedUser.photoUrl
}); });
await user.save(); await user.save();
} else { } else {
// Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями // Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями
if (telegramUser.username) { if (normalizedUser.username) {
user.username = telegramUser.username; user.username = normalizedUser.username;
} else if (!user.username && telegramUser.first_name) { } else if (!user.username && normalizedUser.firstName) {
// Если username пустой, использовать first_name как fallback // Если username пустой, использовать firstName как fallback
user.username = telegramUser.first_name; user.username = normalizedUser.firstName;
} }
if (telegramUser.first_name) { if (normalizedUser.firstName) {
user.firstName = telegramUser.first_name; user.firstName = normalizedUser.firstName;
} }
if (telegramUser.last_name !== undefined) { if (normalizedUser.lastName !== undefined) {
user.lastName = telegramUser.last_name || ''; user.lastName = normalizedUser.lastName;
} }
// Обновлять аватарку только если есть новая // Обновлять аватарку только если есть новая
if (telegramUser.photo_url) { if (normalizedUser.photoUrl) {
user.photoUrl = telegramUser.photo_url; user.photoUrl = normalizedUser.photoUrl;
} }
await user.save(); await user.save();
@ -185,11 +202,13 @@ const authenticate = async (req, res, next) => {
return res.status(403).json({ error: 'Пользователь заблокирован' }); return res.status(403).json({ error: 'Пользователь заблокирован' });
} }
// Подтянуть отсутствующие данные из Telegram (используем нормализованные данные)
await ensureUserData(user, normalizedUser);
await ensureUserSettings(user); await ensureUserSettings(user);
await touchUserActivity(user); await touchUserActivity(user);
req.user = user; req.user = user;
req.telegramUser = telegramUser; req.telegramUser = normalizedUser;
next(); next();
} catch (error) { } catch (error) {
console.error('❌ Ошибка авторизации:', error); console.error('❌ Ошибка авторизации:', error);
@ -254,37 +273,40 @@ const authenticateModeration = async (req, res, next) => {
return res.status(401).json({ error: 'Неверный ID пользователя' }); 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) { if (!user) {
user = new User({ user = new User({
telegramId: telegramUser.id.toString(), telegramId: normalizedUser.id.toString(),
username: telegramUser.username || telegramUser.first_name || 'user', username: normalizedUser.username || normalizedUser.firstName || 'user',
firstName: telegramUser.first_name || '', firstName: normalizedUser.firstName,
lastName: telegramUser.last_name || '', lastName: normalizedUser.lastName,
photoUrl: telegramUser.photo_url || null photoUrl: normalizedUser.photoUrl
}); });
await user.save(); await user.save();
} else { } else {
// Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями // Обновлять только если есть новые данные, не перезаписывать существующие пустыми значениями
if (telegramUser.username) { if (normalizedUser.username) {
user.username = telegramUser.username; user.username = normalizedUser.username;
} else if (!user.username && telegramUser.first_name) { } else if (!user.username && normalizedUser.firstName) {
// Если username пустой, использовать first_name как fallback // Если username пустой, использовать firstName как fallback
user.username = telegramUser.first_name; user.username = normalizedUser.firstName;
} }
if (telegramUser.first_name) { if (normalizedUser.firstName) {
user.firstName = telegramUser.first_name; user.firstName = normalizedUser.firstName;
} }
if (telegramUser.last_name !== undefined) { if (normalizedUser.lastName !== undefined) {
user.lastName = telegramUser.last_name || ''; user.lastName = normalizedUser.lastName;
} }
// Обновлять аватарку только если есть новая // Обновлять аватарку только если есть новая
if (telegramUser.photo_url) { if (normalizedUser.photoUrl) {
user.photoUrl = telegramUser.photo_url; user.photoUrl = normalizedUser.photoUrl;
} }
await user.save(); await user.save();
@ -294,13 +316,13 @@ const authenticateModeration = async (req, res, next) => {
return res.status(403).json({ error: 'Пользователь заблокирован' }); return res.status(403).json({ error: 'Пользователь заблокирован' });
} }
// Подтянуть отсутствующие данные из Telegram // Подтянуть отсутствующие данные из Telegram (используем нормализованные данные)
await ensureUserData(user, telegramUser); await ensureUserData(user, normalizedUser);
await ensureUserSettings(user); await ensureUserSettings(user);
await touchUserActivity(user); await touchUserActivity(user);
req.user = user; req.user = user;
req.telegramUser = telegramUser; req.telegramUser = normalizedUser;
next(); next();
} catch (error) { } catch (error) {
console.error('❌ Ошибка авторизации модерации:', error); console.error('❌ Ошибка авторизации модерации:', error);

37
fix-docker-error.sh Normal file
View File

@ -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"