fix: PostgreSQL compatibility and Telegram bot token validation
- Fixed PostgreSQL 18+ compatibility by using postgres:17 image - Added token validation for Telegram bot - Improved error handling in telegram_bot.py - Added scripts for bot token management - Cleaned up old QR codes and added new utility files
2
bin/migrate.sh
Normal file → Executable file
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run migrations
|
||||
docker exec ${} python3 smartsoltech/manage.py migrate
|
||||
docker exec ${django_app} python3 smartsoltech/manage.py migrate
|
||||
@@ -2,8 +2,8 @@ version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
postgres_db:
|
||||
image: postgres:17
|
||||
container_name: postgres_db
|
||||
env_file: .env
|
||||
volumes:
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
container_name: pgadmin
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- db
|
||||
- postgres_db
|
||||
ports:
|
||||
- "8080:80"
|
||||
environment:
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- db
|
||||
- postgres_db
|
||||
networks:
|
||||
- web_db_network
|
||||
|
||||
|
||||
48
endpoint_test.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASE_URL="http://localhost:8002/auth"
|
||||
EMAIL="testuser@example.com"
|
||||
PASSWORD="secret123"
|
||||
|
||||
echo "1️⃣ Регистрация пользователя..."
|
||||
curl -s -X POST "$BASE_URL/register" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"email\": \"$EMAIL\", \"password\": \"$PASSWORD\"}" | tee response_register.json
|
||||
echo -e "\n"
|
||||
|
||||
USER_ID=$(jq .id response_register.json)
|
||||
|
||||
echo "2️⃣ Аутентификация..."
|
||||
curl -s -X POST "$BASE_URL/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"email\": \"$EMAIL\", \"password\": \"$PASSWORD\"}" | tee response_login.json
|
||||
echo -e "\n"
|
||||
|
||||
TOKEN=$(jq -r .access_token response_login.json)
|
||||
|
||||
echo "🔐 Получен токен: $TOKEN"
|
||||
AUTH_HEADER="Authorization: Bearer $TOKEN"
|
||||
|
||||
echo "3️⃣ Получение текущего пользователя (/me)..."
|
||||
curl -s -X GET "$BASE_URL/me" -H "$AUTH_HEADER" | tee response_me.json
|
||||
echo -e "\n"
|
||||
|
||||
echo "4️⃣ Получение списка всех пользователей..."
|
||||
curl -s -X GET "$BASE_URL/users" | tee response_users.json
|
||||
echo -e "\n"
|
||||
|
||||
echo "5️⃣ Получение пользователя по ID ($USER_ID)..."
|
||||
curl -s -X GET "$BASE_URL/users/$USER_ID" | tee response_user.json
|
||||
echo -e "\n"
|
||||
|
||||
echo "6️⃣ Обновление пользователя..."
|
||||
curl -s -X PUT "$BASE_URL/users/$USER_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"email\": \"updated_$EMAIL\", \"role\": \"admin\"}" | tee response_update.json
|
||||
echo -e "\n"
|
||||
|
||||
echo "7️⃣ Удаление пользователя..."
|
||||
curl -s -X DELETE "$BASE_URL/users/$USER_ID" | tee response_delete.json
|
||||
echo -e "\n"
|
||||
|
||||
echo "✅ Тест завершён."
|
||||
1
response_delete.json
Normal file
@@ -0,0 +1 @@
|
||||
{"detail":"User 4 deleted"}
|
||||
1
response_login.json
Normal file
@@ -0,0 +1 @@
|
||||
{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0Iiwicm9sZSI6InVzZXIiLCJleHAiOjE3NTI0OTc2NDV9.S_tquLFIPnyG6XlfwIw97hJv0l9oKpTcYw_XG0mDd6w","token_type":"bearer"}
|
||||
1
response_me.json
Normal file
@@ -0,0 +1 @@
|
||||
{"id":4,"email":"testuser@example.com","role":"user"}
|
||||
1
response_register.json
Normal file
@@ -0,0 +1 @@
|
||||
{"id":4,"email":"testuser@example.com","role":"user"}
|
||||
1
response_update.json
Normal file
@@ -0,0 +1 @@
|
||||
{"id":4,"email":"updated_testuser@example.com","role":"admin"}
|
||||
1
response_user.json
Normal file
@@ -0,0 +1 @@
|
||||
{"id":4,"email":"testuser@example.com","role":"user"}
|
||||
1
response_users.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"id":1,"email":"user1@example.com","role":"user"},{"id":4,"email":"testuser@example.com","role":"user"}]
|
||||
@@ -14,12 +14,35 @@ class TelegramBot:
|
||||
def __init__(self):
|
||||
# Получение настроек бота из базы данных
|
||||
bot_settings = TelegramSettings.objects.first()
|
||||
if bot_settings:
|
||||
TELEGRAM_BOT_TOKEN = bot_settings.bot_token
|
||||
self.bot = telebot.TeleBot(TELEGRAM_BOT_TOKEN)
|
||||
logging.info("[TelegramBot] Бот инициализирован с токеном.")
|
||||
if bot_settings and bot_settings.bot_token:
|
||||
TELEGRAM_BOT_TOKEN = bot_settings.bot_token.strip()
|
||||
|
||||
# Проверяем валидность токена
|
||||
if self._validate_token(TELEGRAM_BOT_TOKEN):
|
||||
self.bot = telebot.TeleBot(TELEGRAM_BOT_TOKEN)
|
||||
logging.info(f"[TelegramBot] Бот инициализирован с токеном для {bot_settings.bot_name}.")
|
||||
else:
|
||||
logging.error(f"[TelegramBot] Токен невалиден: {TELEGRAM_BOT_TOKEN[:10]}...")
|
||||
raise Exception(f"Невалидный токен Telegram бота. Обновите токен в базе данных.")
|
||||
else:
|
||||
raise Exception("Telegram bot settings not found")
|
||||
raise Exception("Telegram bot settings not found or token is empty")
|
||||
|
||||
def _validate_token(self, token):
|
||||
"""Проверяет валидность токена через Telegram API"""
|
||||
url = f"https://api.telegram.org/bot{token}/getMe"
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
result = response.json()
|
||||
if result.get('ok'):
|
||||
bot_info = result.get('result', {})
|
||||
logging.info(f"[TelegramBot] Токен валиден. Бот: @{bot_info.get('username', 'unknown')}")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"[TelegramBot] Ошибка Telegram API: {result.get('description', 'Unknown error')}")
|
||||
return False
|
||||
except requests.RequestException as e:
|
||||
logging.error(f"[TelegramBot] Ошибка при проверке токена: {e}")
|
||||
return False
|
||||
|
||||
def start_bot_polling(self):
|
||||
logging.info("[TelegramBot] Бот начал работу в режиме polling.")
|
||||
|
||||
|
After Width: | Height: | Size: 69 KiB |
BIN
smartsoltech/media/static/img/project/3.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
smartsoltech/media/static/img/services/1_j0npR4p.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 119 KiB |
@@ -29,9 +29,11 @@ SECRET_KEY = config('SECRET_KEY')
|
||||
DEBUG = True
|
||||
|
||||
# Allowed hosts and CSRF trusted origins
|
||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='').split(',')
|
||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='localhost').split(',')
|
||||
CSRF_TRUSTED_ORIGINS = config('CSRF_TRUSTED_ORIGINS', default='').split(',')
|
||||
|
||||
print(f"ALLOWED_HOSTS: {ALLOWED_HOSTS}")
|
||||
print(f"CSRF_TRUSTED_ORIGINS: {CSRF_TRUSTED_ORIGINS}")
|
||||
|
||||
# Application definition
|
||||
|
||||
|
||||
BIN
smartsoltech/static/qr_codes/request_3.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
BIN
smartsoltech/static/qr_codes/request_4.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
BIN
smartsoltech/static/qr_codes/request_5.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
smartsoltech/static/qr_codes/request_6.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
@@ -7,7 +7,7 @@
|
||||
<div class="row mb-5">
|
||||
<div class="col-md-8 col-xl-6 text-center mx-auto">
|
||||
<h2>Contact us</h2>
|
||||
<p class="w-lg-50">Curae hendrerit donec commodo hendrerit egestas tempus, turpis facilisis nostra nunc. Vestibulum dui eget ultrices.</p>
|
||||
<p class="w-lg-50"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex justify-content-center">
|
||||
@@ -28,7 +28,7 @@
|
||||
</svg></div>
|
||||
<div class="px-2">
|
||||
<h6 class="mb-0">Email</h6>
|
||||
<p class="mb-0"><a href="mailto:a.choi@smartsoltech.kr">a.choI@smartsoltech.kr</a></p>
|
||||
<p class="mb-0"><a href="mailto:a.choi@smartsoltech.kr">a.choi@smartsoltech.kr</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center p-3">
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<link rel="manifest" href="/static/manifest.json">
|
||||
<script src="{% static 'assets/js/modal-init.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'assets/css/modal-styles.css' %}">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="{% static 'assets/js/modal-init.js' %}"></script>
|
||||
<title>{% block title %}Smartsoltech{% endblock %}</title>
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
<a class="nav-link" href="{% url 'home' %}">Главная</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Услуги</a>
|
||||
<a class="nav-link" href="{% url 'services' %}">Услуги</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Контакты</a>
|
||||
<a class="nav-link" href="{% url 'about' %}">Контакты</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
</svg></span><span>SmartSolTech</span></a><button class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navcol-5"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||
<div id="navcol-5" class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item"><a class="nav-link active" href="/services/">Услуги</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#">Наши проекты</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/about/">О нас</a></li>
|
||||
<li class="nav-item"><a class="nav-link active" href="{% url 'services' %}">Услуги</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="{% url 'about_view' %}">О нас</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
50
update_bot_token.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
# Скрипт для обновления токена Telegram бота
|
||||
# Использование: ./update_bot_token.sh "НОВЫЙ_ТОКЕН"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "❌ Ошибка: Необходимо указать токен"
|
||||
echo "Использование: $0 \"НОВЫЙ_ТОКЕН\""
|
||||
echo ""
|
||||
echo "Пример: $0 \"1234567890:ABCDEFghijklmnopqrstuvwxyz\""
|
||||
echo ""
|
||||
echo "Получите токен от @BotFather в Telegram:"
|
||||
echo "1. Отправьте /mybots"
|
||||
echo "2. Выберите своего бота"
|
||||
echo "3. Нажмите 'API Token'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_TOKEN="$1"
|
||||
|
||||
echo "🔄 Обновление токена Telegram бота..."
|
||||
|
||||
# Проверяем валидность токена
|
||||
echo "🔍 Проверка валидности токена..."
|
||||
RESPONSE=$(curl -s "https://api.telegram.org/bot${NEW_TOKEN}/getMe")
|
||||
if echo "$RESPONSE" | grep -q '"ok":true'; then
|
||||
BOT_USERNAME=$(echo "$RESPONSE" | grep -o '"username":"[^"]*"' | cut -d'"' -f4)
|
||||
echo "✅ Токен валиден! Бот: @${BOT_USERNAME}"
|
||||
else
|
||||
echo "❌ Ошибка: Токен невалиден!"
|
||||
echo "Ответ API: $RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Обновляем токен в базе данных
|
||||
echo "💾 Обновление токена в базе данных..."
|
||||
docker exec postgres_db psql -U trevor -d 2st_db -c "
|
||||
UPDATE comunication_telegramsettings
|
||||
SET bot_token = '$NEW_TOKEN', bot_name = '@${BOT_USERNAME}'
|
||||
WHERE id = 1;
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Токен успешно обновлен в базе данных!"
|
||||
echo "🔄 Перезапуск контейнера telegram_bot..."
|
||||
docker restart telegram_bot
|
||||
echo "🎉 Готово! Проверьте логи: docker logs telegram_bot"
|
||||
else
|
||||
echo "❌ Ошибка при обновлении базы данных"
|
||||
exit 1
|
||||
fi
|
||||
104
update_telegram_token.py
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для обновления токена Telegram бота в базе данных
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import django
|
||||
import requests
|
||||
|
||||
# Настройка Django
|
||||
sys.path.append('/app/smartsoltech')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'smartsoltech.settings')
|
||||
django.setup()
|
||||
|
||||
from comunication.models import TelegramSettings
|
||||
|
||||
def validate_token(token):
|
||||
"""Проверяет валидность токена через Telegram API"""
|
||||
url = f"https://api.telegram.org/bot{token}/getMe"
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
return response.json().get('ok', False)
|
||||
except requests.RequestException:
|
||||
return False
|
||||
|
||||
def update_telegram_token(new_token, bot_name=None):
|
||||
"""Обновляет токен Telegram бота в базе данных"""
|
||||
|
||||
# Проверяем валидность токена
|
||||
if not validate_token(new_token):
|
||||
print(f"❌ Ошибка: Токен {new_token} невалиден!")
|
||||
return False
|
||||
|
||||
# Получаем информацию о боте
|
||||
url = f"https://api.telegram.org/bot{new_token}/getMe"
|
||||
response = requests.get(url)
|
||||
bot_info = response.json()
|
||||
|
||||
if bot_info.get('ok'):
|
||||
bot_username = bot_info['result']['username']
|
||||
print(f"✅ Токен валиден. Бот: @{bot_username}")
|
||||
|
||||
# Обновляем настройки в базе данных
|
||||
telegram_settings, created = TelegramSettings.objects.get_or_create(
|
||||
id=1,
|
||||
defaults={
|
||||
'bot_name': f"@{bot_username}",
|
||||
'bot_token': new_token,
|
||||
'use_polling': True
|
||||
}
|
||||
)
|
||||
|
||||
if not created:
|
||||
telegram_settings.bot_token = new_token
|
||||
telegram_settings.bot_name = bot_name or f"@{bot_username}"
|
||||
telegram_settings.save()
|
||||
print(f"✅ Токен обновлен в базе данных для бота {telegram_settings.bot_name}")
|
||||
else:
|
||||
print(f"✅ Создана новая запись для бота @{bot_username}")
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"❌ Ошибка при получении информации о боте")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🤖 Скрипт обновления токена Telegram бота")
|
||||
print("=" * 50)
|
||||
|
||||
# Проверяем текущий токен
|
||||
try:
|
||||
current_settings = TelegramSettings.objects.first()
|
||||
if current_settings:
|
||||
print(f"Текущий бот: {current_settings.bot_name}")
|
||||
print(f"Текущий токен: {current_settings.bot_token[:10]}...")
|
||||
|
||||
if not validate_token(current_settings.bot_token):
|
||||
print("❌ Текущий токен невалиден")
|
||||
else:
|
||||
print("✅ Текущий токен валиден")
|
||||
else:
|
||||
print("⚠️ Настройки Telegram бота не найдены")
|
||||
except Exception as e:
|
||||
print(f"❌ Ошибка при проверке текущих настроек: {e}")
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Для обновления токена:")
|
||||
print("1. Идите к @BotFather в Telegram")
|
||||
print("2. Создайте нового бота или используйте /token для существующего")
|
||||
print("3. Скопируйте токен и введите его ниже")
|
||||
print("=" * 50)
|
||||
|
||||
new_token = input("\nВведите новый токен бота (или 'exit' для выхода): ").strip()
|
||||
|
||||
if new_token.lower() == 'exit':
|
||||
print("Выход...")
|
||||
sys.exit(0)
|
||||
|
||||
if update_telegram_token(new_token):
|
||||
print("\n🎉 Токен успешно обновлен!")
|
||||
print("Теперь перезапустите контейнер telegram_bot:")
|
||||
print("docker restart telegram_bot")
|
||||
else:
|
||||
print("\n❌ Не удалось обновить токен")
|
||||