Добавление промо кода по запросу

main
pilot 2 months ago
parent 37007e6caf
commit 5b806651e3

@ -373,3 +373,26 @@ def maxbot_send_link_button(text, title_button, link, chat_id, max_token):
response = requests.request("POST", url, headers=headers, data=payload, verify=max_verify)
rt = {'success': True, 'error': '', 'data': response}
def maxbot_set_commands(max_token: str, commands: list) -> requests.Response:
"""
Устанавливает команды для бота через PATCH /me/commands.
Аргументы:
max_token: токен авторизации бота
commands: список словарей с полями name и description
Пример:
commands = [
{"name": "start", "description": "Начать работу с ботом"},
{"name": "menu", "description": "Показать меню"}
]
Возвращает объект Response.
"""
url = f"{url_max}/me/commands"
headers = {
'Authorization': f'{max_token}',
'Content-Type': 'application/json'
}
payload = {"commands": commands}
response = requests.patch(url, headers=headers, json=payload, verify=max_verify)
return response

@ -1,3 +1,55 @@
from django.test import TestCase
from unittest.mock import patch, MagicMock
from max_bot.max_api import maxbot_set_commands
# Create your tests here.
class MaxApiCommandsTest(TestCase):
"""Тесты для функции maxbot_set_commands."""
@patch('max_bot.max_api.requests.patch')
def test_maxbot_set_commands_success(self, mock_patch):
"""Проверка успешного создания команд."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {'success': True}
mock_patch.return_value = mock_response
max_token = 'test_token'
commands = [
{'name': 'start', 'description': 'Начать'},
{'name': 'menu', 'description': 'Меню'}
]
response = maxbot_set_commands(max_token, commands)
mock_patch.assert_called_once_with(
'https://platform-api2.max.ru/me/commands',
headers={
'Authorization': 'test_token',
'Content-Type': 'application/json'
},
json={'commands': commands},
verify=mock_patch.call_args[1].get('verify')
)
self.assertEqual(response, mock_response)
@patch('max_bot.max_api.requests.patch')
def test_maxbot_set_commands_empty_list(self, mock_patch):
"""Проверка передачи пустого списка команд."""
mock_response = MagicMock()
mock_response.status_code = 200
mock_patch.return_value = mock_response
response = maxbot_set_commands('token', [])
mock_patch.assert_called_once()
self.assertEqual(response, mock_response)
@patch('max_bot.max_api.requests.patch')
def test_maxbot_set_commands_error_response(self, mock_patch):
"""Проверка обработки ошибки API."""
mock_response = MagicMock()
mock_response.status_code = 400
mock_response.json.return_value = {'error': 'Bad Request'}
mock_patch.return_value = mock_response
response = maxbot_set_commands('token', [{'name': 'test', 'description': 'test'}])
self.assertEqual(response.status_code, 400)

@ -0,0 +1,54 @@
# promo_handlers.py
import qrcode
from max_bot.models import Client, PromoCode
from restoran_max_bot.common import common_get_data
from restoran_max_bot.message_sender import send_text, send_image
from restoran_max_bot.settings import STATICFILES_DIRS, BASE_URL
def bot_promo(client: Client, message: dict, settings_max: dict) -> bool:
"""Обработчик промокодов (QR-коды)."""
chat_id = message['chat_id']
promo = message['payload'].lower()
messenger = 'max-bot'
client_id = client.id
data = common_get_data(client=client, key=promo)
if not data:
return True
promo_obj, created = PromoCode.objects.get_or_create(
promo=promo,
chat_id=chat_id,
client=client,
defaults={'messenger': messenger, 'used': False}
)
if not created:
if promo_obj.used:
send_text(chat_id, settings_max['token'], "⚠️ Этот промокод уже был использован.")
else:
send_text(chat_id, settings_max['token'], " QR-код уже был отправлен.")
return True
# Генерируем QR
base_url = f"{BASE_URL}/promo/status/"
url_promo = f"{base_url}{promo}/{chat_id}/{client_id}"
img = qrcode.make(url_promo)
file_name = f"{promo}-{chat_id}-{client_id}.png"
img.save(f"{STATICFILES_DIRS[0]}/client_qr/{file_name}")
qr_url = f"{BASE_URL}/static/client_qr/{file_name}"
send_image(chat_id, settings_max['token'], qr_url, 'Ваш QR-код.')
# Отправляем дополнительный контент
for item in data:
if item.img:
img_url = f"https://cdn.telefon-ip.ru/{item.img}?thumb=600"
send_image(chat_id, settings_max['token'], img_url, item.descr)
if item.title and not item.img:
send_text(chat_id, settings_max['token'], item.descr)
if item.url:
send_text(chat_id, settings_max['token'], item.url)
return True

@ -0,0 +1,55 @@
# user_logger.py
import json
import os
from datetime import datetime
from threading import Lock
from max_bot.models import Client
# Папка для логов активности пользователей
LOG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'log', 'user_activity')
os.makedirs(LOG_DIR, exist_ok=True)
_lock = Lock()
def log_user_action(
client: Client,
chat_id: str,
action_type: str,
details: dict = None,
user_query: str = None,
intent: str = None,
entities: dict = None,
response: str = None,
command: str = None
) -> None:
"""
Логирует действие пользователя в структурированном JSON-формате.
Запись добавляется в файл user_activity_YYYY-MM-DD.log.
"""
timestamp = datetime.now().isoformat()
log_entry = {
"timestamp": timestamp,
"client_id": client.id,
"chat_id": chat_id,
"action_type": action_type,
"details": details or {},
}
if user_query is not None:
log_entry["user_query"] = user_query
if intent is not None:
log_entry["intent"] = intent
if entities is not None:
log_entry["entities"] = entities
if response is not None:
log_entry["response"] = response
if command is not None:
log_entry["command"] = command
# Определяем имя файла по дате
date_str = datetime.now().strftime("%Y-%m-%d")
log_file = os.path.join(LOG_DIR, f"user_activity_{date_str}.log")
# Потокобезопасная запись
with _lock:
with open(log_file, 'a', encoding='utf-8') as f:
f.write(json.dumps(log_entry, ensure_ascii=False) + '\n')
Loading…
Cancel
Save