diff --git a/README.md b/README.md index 535126c..0450ad7 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ AUTH_API - уникальный набор символов, для взаимо - [x] Написать базовый функционал ~~- [ ] Создать соотношение типа "id_пользователя: досутп_к_замку:"~~ - [x] Сделать проверку пользователей по их номеру телефона ... -- [ ] Создать и парсить json с информацией о пользователях и их номерах -- [ ] Проверять, является ли пользователь администратором, если является - выводить дополнительную кнопку, предлагающую добавить номер в БД +- [x] Удалить модуль getenv +- [x] Создать и парсить json с информацией о пользователях и их номерах +~~- [ ] Проверять, является ли пользователь администратором, если является, выводить дополнительную кнопку, предлагающую добавить номер в БД~~ - [ ] Сделать логирование о том, что кто-то открыл дверь в конкретное время diff --git a/auth.py b/auth.py index 1102056..156262e 100644 --- a/auth.py +++ b/auth.py @@ -1,6 +1,8 @@ -ALLOWED_PHONE_NUMBERS = [ - "+79000959392", -] +from config import config +import re + + +ALLOWED_PHONE_NUMBERS = list(config.get("users", {}).keys()) AUTHORIZED_USERS = {} @@ -9,13 +11,26 @@ def check_user_auth(phone: str) -> bool: return phone in ALLOWED_PHONE_NUMBERS +def normalize_phone(phone: str) -> str: + phone = phone.strip() + phone = re.sub(r"[^\d+]", "", phone) + if not phone.startswith("+"): + phone = "+" + phone + return phone + + def authorize_user(user_id: int, phone: str) -> bool: - if check_user_auth(phone): - AUTHORIZED_USERS[user_id] = phone - print(f"{user_id} авторизован с номером: {phone}") + normalized_phone = normalize_phone(phone) + if normalized_phone in ALLOWED_PHONE_NUMBERS: + AUTHORIZED_USERS[user_id] = normalized_phone + # if check_user_auth(phone): + # AUTHORIZED_USERS[user_id] = phone + print(f"{user_id} авторизован с номером: {normalized_phone}") return True else: - print(f"Пользователь {user_id} пытался авторизоваться с номером {phone}") + print( + f"Пользователь {user_id} пытался авторизоваться с номером {normalized_phone}" + ) return False diff --git a/bot_config.json b/bot_config.json new file mode 100644 index 0000000..f40b700 --- /dev/null +++ b/bot_config.json @@ -0,0 +1,23 @@ +{ + "bot_token": "", + "locks": { + "Room418": { + "ip": "10.9.1.26", + "auth_api": "73B15D12" + }, + "Floor4": { + "ip": "10.9.1.27", + "auth_api": "F901C40A" + } + }, + "users": { + "+79000959392": { + "access_card": "000D001195DD", + "lock_id": ["Room418", "Floor4"] + }, + "+79221716513": { + "access_card": "", + "lock_id": ["Room418", "Floor4"] + } + } +} diff --git a/buttons.py b/buttons.py deleted file mode 100755 index 98bb0bf..0000000 --- a/buttons.py +++ /dev/null @@ -1,7 +0,0 @@ -from aiogram.utils.keyboard import ReplyKeyboardBuilder - -def FBI_open_up(): - kb = ReplyKeyboardBuilder() - kb.button(text = "Сизам вскройся") - - return kb.as_markup(resize_keyboard = True) \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..54cdee5 --- /dev/null +++ b/config.py @@ -0,0 +1,11 @@ +import json + +CONFIG_PATH = "bot_config.json" + + +def load_config(path: str = CONFIG_PATH) -> dict: + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + + +config = load_config() diff --git a/handlers/contact_handler.py b/handlers/contact_handler.py index 2c6bd35..61a9a94 100644 --- a/handlers/contact_handler.py +++ b/handlers/contact_handler.py @@ -1,8 +1,9 @@ from aiogram import Dispatcher, F from aiogram.types import Message -from keyboard import get_keyboard -from auth import authorize_user +from keyboard import get_locks_keyboard, get_contact_keyboard +from auth import authorize_user, normalize_phone +from config import config def register_contact_handler(dp: Dispatcher): @@ -14,12 +15,22 @@ def register_contact_handler(dp: Dispatcher): await msg.answer("Ошибка: номер телефона не получен") return - phone = msg.contact.phone_number - print(f"Номер {phone} получен от пользователя {user_id}") + phone = normalize_phone(msg.contact.phone_number) if not authorize_user(user_id, phone): - await msg.answer("Доступ запрещен, номер не авторизирован") + await msg.answer("Доступ запрещен, номер не идентифицирован") return + + user_conf = config.get("users", {}).get(phone) + print(f"***user_conf для {phone}: {user_conf}***") + if not user_conf: + await msg.answer("Пользователь не опознан") + return + + allowed_locks = user_conf.get("lock_id", []) + print(f"***allowed_locks = {allowed_locks}***") + reply_markup = get_locks_keyboard(allowed_locks) + await msg.answer( - "Номер подтвержден", reply_markup=get_keyboard(authorized=True) + "Номер подтвержден. Выберите дверь для открытия", reply_markup=reply_markup ) diff --git a/handlers/doors_handler.py b/handlers/doors_handler.py index e137e9e..7609c41 100644 --- a/handlers/doors_handler.py +++ b/handlers/doors_handler.py @@ -1,30 +1,66 @@ import asyncio import requests -from os import getenv -from aiogram import Dispatcher, F +from aiogram import Dispatcher from aiogram.types import Message -from auth import is_user_auth + +from auth import AUTHORIZED_USERS, is_user_auth +from config import config def register_open_door_handler(dp: Dispatcher): - @dp.message(F.text == "Открыть дверь") + @dp.message() async def open_door_handler(msg: Message): + print( + f"DEBUG: Получено сообщение от пользователя {msg.from_user.id}: '{msg.text}'" + ) user_id = msg.from_user.id if not is_user_auth(user_id): await msg.answer( "Доступ запрщен. Необходимо предоставить свой номер телефона." ) + else: + print("OK") + + phone = AUTHORIZED_USERS.get(user_id) + print(AUTHORIZED_USERS) + print(f"***user_id={user_id},phone={phone}***") + user_conf = config.get("users", {}).get(phone) + print(f"***phone={phone}, user_conf={user_conf}***") + # allowed_locks = user_conf.get("locks", []) + # print(f"***allowed_locks={allowed_locks}***") + + # if msg.text not in allowed_locks: + # print("**********************") + # print(f"***{allowed_locks}***") + # print(f"***{msg.text}***") + # print("**********************") + # return + + lock_conf = config.get("locks", {}).get(msg.text) + if not lock_conf: + await msg.answer("Информации по замку не найдено") return - url = f"http://{getenv('LOCK_IP')}/cgi-bin/ext" - auth = ("ext", f"{getenv('AUTH_API')}") - payload = f"CARD={getenv('CARD_ID')}&DIR=0" + url = f"http://{lock_conf['ip']}/cgi-bin/ext" + auth_info = ("ext", lock_conf["auth_api"]) + payload = f"CARD={user_conf['access_card']}&DIR=0" headers = {"Content-Type": "application/x-www-form-urlencoded"} try: + print( + f"***DEBUG: Отправляю запрос к {url} c payload: {payload} и auth: {auth_info}" + ) response = await asyncio.to_thread( - requests.post, url, auth=auth, data=payload, headers=headers, timeout=5 + requests.post, + url, + auth=auth_info, + data=payload, + headers=headers, + timeout=5, + ) + print( + f"DEBUG: URL: {url}, status: {response.status_code}, response: {response.text}" ) if response.status_code == 200: await msg.answer("Открыто") diff --git a/handlers/start_handler.py b/handlers/start_handler.py index de48615..a2d0865 100644 --- a/handlers/start_handler.py +++ b/handlers/start_handler.py @@ -2,8 +2,9 @@ from aiogram import Dispatcher, F from aiogram.types import Message from aiogram.filters import CommandStart -from keyboard import get_keyboard -from auth import is_user_auth +from keyboard import get_contact_keyboard, get_locks_keyboard +from auth import is_user_auth, AUTHORIZED_USERS +from config import config def register_start_handler(dp: Dispatcher): @@ -11,11 +12,25 @@ def register_start_handler(dp: Dispatcher): async def command_start_handler(msg: Message): user_id = msg.from_user.id if is_user_auth(user_id): + phone = AUTHORIZED_USERS.get(user_id) + if not phone: + await msg.answer("Номер не найден") + return + + user_conf = config.get("user", {}).get(phone) + if not user_conf: + await msg.answer("Пользователь не найден в конфигурации") + return + + allowed_locks = user_conf.get("locks_id", []) + reply_markup = get_locks_keyboard(allowed_locks) await msg.answer( - "Авторизация прошла успешно", reply_markup=get_keyboard(authorized=True) + "Авторизация прошла успешно", + reply_markup=reply_markup, ) else: + reply_markup = get_contact_keyboard() await msg.answer( "Для пользования ботом, предоставьте номер телефона", - reply_markup=get_keyboard(authorized=False), + reply_markup=reply_markup, ) diff --git a/keyboard.py b/keyboard.py index c114510..7ae5f72 100755 --- a/keyboard.py +++ b/keyboard.py @@ -1,11 +1,16 @@ -from aiogram.utils.keyboard import ReplyKeyboardBuilder, KeyboardButton +from aiogram.utils.keyboard import ReplyKeyboardBuilder +from aiogram.types import KeyboardButton -def get_keyboard(authorized: bool): +def get_locks_keyboard(allowed_locks: list): + print(f"DEBUG: allowed_locks = {allowed_locks}") kb = ReplyKeyboardBuilder() - if authorized: - kb.button(text="Открыть дверь") - else: - kb.add(KeyboardButton(text="Поделиться контактом", request_contact=True)) + for lock in allowed_locks: + kb.button(text=lock) return kb.as_markup(resize_keyboard=True) + +def get_contact_keyboard(): + kb = ReplyKeyboardBuilder() + kb.add(KeyboardButton(text="Поделиться контактом", request_contact=True)) + return kb.as_markup(resize_keyboard=True) diff --git a/main.py b/main.py index 281902c..b47c41c 100755 --- a/main.py +++ b/main.py @@ -1,29 +1,23 @@ import asyncio import logging import sys -from os import getenv from aiogram import Bot, Dispatcher from aiogram.enums import ParseMode from aiogram.client.default import DefaultBotProperties from handlers import register_all_handlers -from init_config import check_env_file, create_env_file, load_env +from config import config -if not check_env_file(): - create_env_file() +BOT_TOKEN = config["bot_token"] -load_env() - -TOKEN = getenv("TOKEN") dp = Dispatcher() - register_all_handlers(dp) async def main() -> None: - bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) + bot = Bot(token=BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) await dp.start_polling(bot) diff --git a/requirements.txt b/requirements.txt index dde3192..c49d87d 100755 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,6 @@ multidict==6.4.3 propcache==0.3.1 pydantic==2.11.3 pydantic_core==2.33.1 -python-dotenv==1.1.0 requests==2.32.3 typing-inspection==0.4.0 typing_extensions==4.13.2