JSON was remove
BOT_open_sesam/pipeline/head This commit looks good Details

Теперь вся информация получается по запросам к API, локально хранится
только BOT_TOKEN в файле .env
test
dl 2025-05-29 17:10:51 +05:00
parent e319ea2e73
commit 3b5ac43c30
10 changed files with 81 additions and 60 deletions

1
.env 100644
View File

@ -0,0 +1 @@
BOT_TOKEN=

View File

@ -9,3 +9,4 @@
- [x] Изменить json хранящийся локально на запросы к API - [x] Изменить json хранящийся локально на запросы к API
- [x] Изменить названия комнта в локальном json - [x] Изменить названия комнта в локальном json
- [x] Ограничить логи внутри докера - [x] Ограничить логи внутри докера
- [x] Избавиться от json файла, переместить токен в .env файл, информацию от замков получать через запрос по API

12
auth.py
View File

@ -1,4 +1,3 @@
from config import config
import re import re
import aiohttp import aiohttp
@ -6,25 +5,18 @@ AUTHORIZED_USERS = {}
def normalize_phone(phone: str) -> str: def normalize_phone(phone: str) -> str:
print(phone)
digits = re.sub(r"\D", "", phone) digits = re.sub(r"\D", "", phone)
if len(digits) > 10: if len(digits) > 10:
digits = digits[-10:] digits = digits[-10:]
print(digits)
return digits return digits
async def authorize_user(user_id: int, phone: str) -> bool: async def authorize_user(user_id: int, phone: str) -> bool:
normalized = normalize_phone(phone) normalized = normalize_phone(phone)
api_url = config.get("user_api_url") api_url = "https://papi.dataekb.ru/check_access"
if not api_url:
print("Не указан user_api_url в конфигурации")
return False
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
try: try:
async with session.get(api_url, params={"tel": normalized}) as response: async with session.get(api_url, params={"tel": normalized}) as response:
print(response.status)
if response.status != 200: if response.status != 200:
print(f"Ошибка запроса к API: статус {response.status}") print(f"Ошибка запроса к API: статус {response.status}")
return False return False
@ -34,7 +26,7 @@ async def authorize_user(user_id: int, phone: str) -> bool:
return False return False
if data.get("response") != "1": if data.get("response") != "1":
print(f"Доступ запрещен для номера: {normalized}") print(f"Доступ запрещён для номера: {normalized}")
return False return False
zone_str = data["data"].get("zone", "") zone_str = data["data"].get("zone", "")

View File

@ -1,11 +1,20 @@
import json def load_env(path=".env") -> dict:
env = {}
CONFIG_PATH = "bot_config.json" try:
def load_config(path: str = CONFIG_PATH) -> dict:
with open(path, "r", encoding="utf-8") as f: with open(path, "r", encoding="utf-8") as f:
return json.load(f) for line in f:
line = line.strip()
# Пропускаем пустые строки и строки-комментарии
if not line or line.startswith("#"):
continue
if "=" in line:
key, value = line.split("=", 1)
env[key.strip()] = value.strip()
except FileNotFoundError:
raise Exception(
f"Файл {path} не найден. Проверьте наличие файла .env в корне проекта."
)
return env
config = load_config() config = load_env()

View File

@ -9,24 +9,22 @@ def register_contact_handler(dp: Dispatcher):
@dp.message(F.contact) @dp.message(F.contact)
async def contact_handler(msg: Message): async def contact_handler(msg: Message):
user_id = msg.from_user.id user_id = msg.from_user.id
if msg.contact is None: if msg.contact is None:
await msg.answer("Ошибка: номер телефона не получен") await msg.answer("Ошибка: номер телефона не получен")
return return
phone = msg.contact.phone_number phone = msg.contact.phone_number
if not await authorize_user(user_id, phone): if not await authorize_user(user_id, phone):
await msg.answer("Доступ запрещен, номер не идентифицирован") await msg.answer("Доступ запрещён, номер не идентифицирован")
return return
user_data = AUTHORIZED_USERS.get(user_id) user_data = AUTHORIZED_USERS.get(user_id)
if not user_data: if not user_data:
await msg.answer("Ошибка получения данных пользователя") await msg.answer("Ошибка авторизации.")
return return
allowed_zones = user_data["zones"] allowed_zones = user_data["zones"]
reply_markup = get_locks_keyboard(allowed_zones) reply_markup = await get_locks_keyboard(allowed_zones)
await msg.answer( await msg.answer(
"Номер подтвержден. Выберите дверь для открытия", reply_markup=reply_markup "Номер подтверждён. Выберите дверь для открытия", reply_markup=reply_markup
) )

View File

@ -5,15 +5,7 @@ from aiogram import Dispatcher
from aiogram.types import Message from aiogram.types import Message
from auth import AUTHORIZED_USERS, is_user_auth from auth import AUTHORIZED_USERS, is_user_auth
from config import config from locks_api import get_lock_by_label
def get_lock_code(display_text: str) -> str:
locks_map = config.get("locks_map", {})
for code, friendly in locks_map.items():
if friendly == display_text:
return code
return display_text
def register_open_door_handler(dp: Dispatcher): def register_open_door_handler(dp: Dispatcher):
@ -21,24 +13,21 @@ def register_open_door_handler(dp: Dispatcher):
async def open_door_handler(msg: Message): async def open_door_handler(msg: Message):
user_id = msg.from_user.id user_id = msg.from_user.id
if not is_user_auth(user_id): if not is_user_auth(user_id):
await msg.answer( await msg.answer("Доступ запрещён. Предоставьте номер телефона.")
"Доступ запрщен. Необходимо предоставить свой номер телефона."
)
return return
user_data = AUTHORIZED_USERS.get(user_id) user_data = AUTHORIZED_USERS.get(user_id)
if not user_data: if not user_data:
await msg.answer("Ошибка авторизации пользователя.") await msg.answer("Ошибка авторизации.")
return return
lock_code = get_lock_code(msg.text) lock_info = await get_lock_by_label(msg.text)
lock_conf = config.get("locks", {}).get(lock_code) if not lock_info:
if not lock_conf: await msg.answer("Информация по замку не найдена.")
await msg.answer("Информации по замку не найдено")
return return
url = f"http://{lock_conf['ip']}/cgi-bin/ext" url = f"http://{lock_info['ip']}/cgi-bin/ext"
auth_info = ("ext", lock_conf["pass"]) auth_info = ("ext", lock_info["code"])
payload = f"CARD={user_data['card']}&DIR=0" payload = f"CARD={user_data['card']}&DIR=0"
headers = {"Content-Type": "application/x-www-form-urlencoded"} headers = {"Content-Type": "application/x-www-form-urlencoded"}

View File

@ -13,18 +13,14 @@ def register_start_handler(dp: Dispatcher):
if is_user_auth(user_id): if is_user_auth(user_id):
user_data = AUTHORIZED_USERS.get(user_id) user_data = AUTHORIZED_USERS.get(user_id)
if not user_data: if not user_data:
await msg.answer("Номер не найден") await msg.answer("Ошибка авторизации.")
return return
allowed_zones = user_data["zones"] allowed_zones = user_data["zones"]
reply_markup = get_locks_keyboard(allowed_zones) reply_markup = await get_locks_keyboard(allowed_zones)
await msg.answer( await msg.answer("Авторизация прошла успешно", reply_markup=reply_markup)
"Авторизация прошла успешно",
reply_markup=reply_markup,
)
else: else:
reply_markup = get_contact_keyboard() reply_markup = get_contact_keyboard()
await msg.answer( await msg.answer(
"Для пользования ботом, предоставьте номер телефона", "Для пользования ботом предоставьте номер телефона",
reply_markup=reply_markup, reply_markup=reply_markup,
) )

View File

@ -1,14 +1,15 @@
from aiogram.utils.keyboard import ReplyKeyboardBuilder from aiogram.utils.keyboard import ReplyKeyboardBuilder
from aiogram.types import KeyboardButton from aiogram.types import KeyboardButton
from config import config from locks_api import fetch_locks
def get_locks_keyboard(allowed_locks: list): async def get_locks_keyboard(allowed_locks: list):
kb = ReplyKeyboardBuilder() kb = ReplyKeyboardBuilder()
locks_map = config.get("locks_map", {}) locks = await fetch_locks()
for lock in allowed_locks: for zone in allowed_locks:
display_text = locks_map.get(lock, lock) lock_info = locks.get(zone)
kb.button(text=display_text) btn_text = lock_info["name"] if lock_info and "name" in lock_info else zone
kb.button(text=btn_text)
return kb.as_markup(resize_keyboard=True) return kb.as_markup(resize_keyboard=True)

35
locks_api.py 100644
View File

@ -0,0 +1,35 @@
import aiohttp
import json
LOCKS_API_URL = "https://papi.dataekb.ru/get_pacs"
async def fetch_locks() -> dict:
async with aiohttp.ClientSession() as session:
try:
async with session.get(LOCKS_API_URL) as response:
if response.status != 200:
print(f"Ошибка при получении данных замков: {response.status}")
return {}
text = await response.text()
except Exception as e:
print(f"Исключение при запросе данных замков: {str(e)}")
return {}
try:
data = json.loads(text)
if not data or not isinstance(data, list):
print("Неверный формат данных о замках, ожидался список.")
return {}
locks_dict = data[0] # предполагается, что список содержит один словарь
return locks_dict
except Exception as e:
print(f"Ошибка при разборе данных замков: {str(e)}")
return {}
async def get_lock_by_label(label: str) -> dict:
locks = await fetch_locks()
for lock_id, details in locks.items():
if label == lock_id or details.get("name") == label:
return details
return {}

View File

@ -9,8 +9,7 @@ from aiogram.client.default import DefaultBotProperties
from handlers import register_all_handlers from handlers import register_all_handlers
from config import config from config import config
BOT_TOKEN = config["BOT_TOKEN"]
BOT_TOKEN = config["bot_token"]
dp = Dispatcher() dp = Dispatcher()
register_all_handlers(dp) register_all_handlers(dp)