- Создан файл .gitignore для исключения временных и сгенерированных файлов. - Добавлен файл .python-version для указания версии Python. - Реализован класс OracleDatabase для работы с базой данных Oracle. - Создан основной файл main.py с логикой бота на aiogram. - Добавлен middleware для работы с сессией базы данных. - Создан файл pyproject.toml для управления зависимостями. - Добавлен README.md с инструкциями по запуску. - Создан скрипт run.cmd для запуска бота с необходимыми переменными окружения. - Добавлен файл uv.lock для управления зависимостями через uv.
103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
import asyncio
|
|
from os import getenv
|
|
import logging
|
|
# import json
|
|
from aiogram import Bot, Dispatcher
|
|
from aiogram.filters import Command
|
|
from aiogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery
|
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
from aiogram.fsm.state import State, StatesGroup
|
|
from aiogram.fsm.context import FSMContext
|
|
from db import OracleDatabase
|
|
from middlewares.db import DbSessionMiddleware
|
|
|
|
|
|
if getenv("DEBUG",'0') == '1':
|
|
logging.basicConfig(level=logging.INFO)
|
|
else:
|
|
logging.basicConfig(level=logging.WARNING)
|
|
|
|
|
|
TOKEN = getenv("BOT_TOKEN")
|
|
BOTNAME = getenv("BOT_NAME")
|
|
# SALVAGEDB_TOKEN=getenv("SALVAGEDB_TOKEN",'1234567890')
|
|
|
|
oracle_db = OracleDatabase(
|
|
user= getenv("db_user"),
|
|
password= getenv("db_password"),
|
|
dsn= getenv("db_dsn")
|
|
)
|
|
|
|
|
|
dp = Dispatcher()
|
|
|
|
class VinStates(StatesGroup):
|
|
waiting_for_vin = State()
|
|
|
|
|
|
# Command handler
|
|
@dp.message(Command("start"))
|
|
async def command_start_handler(message: Message) -> None:
|
|
welcome_text = (
|
|
"Welcome to SalvagedbBot — your trusted assistant for vehicle history checks via VIN!\n\n"
|
|
"🔍 What You Can Discover:\n\n"
|
|
"• Salvage or junk status\n"
|
|
"• Damage from hail, flood, or fire\n"
|
|
"• Mileage discrepancies or odometer rollback\n"
|
|
"• Gray market vehicle status\n\n"
|
|
"We don't claim that a vehicle has a salvage title, but we provide information indicating possible past damages, helping you make informed decisions."
|
|
)
|
|
builder = InlineKeyboardBuilder()
|
|
builder.button(text="Decode VIN", callback_data="decode_vin")
|
|
builder.button(text="Check VIN", callback_data="check_vin")
|
|
builder.button(text="Search car Photo", callback_data="search_car_photo")
|
|
builder.adjust(3)
|
|
builder.button(text="Help", callback_data="help")
|
|
builder.button(text="Prices", callback_data="prices")
|
|
builder.button(text="Go Salvagedb.com", url="https://salvagedb.com")
|
|
builder.adjust(3, 2)
|
|
await message.answer(welcome_text, reply_markup=builder.as_markup())
|
|
|
|
|
|
@dp.callback_query(lambda c: c.data == "decode_vin")
|
|
async def decode_vin_callback(callback: CallbackQuery, state: FSMContext):
|
|
await callback.message.answer("Please enter the vehicle VIN.")
|
|
await state.set_state(VinStates.waiting_for_vin)
|
|
await callback.answer()
|
|
|
|
|
|
@dp.message(VinStates.waiting_for_vin)
|
|
async def process_vin(message: Message, state: FSMContext, db: OracleDatabase):
|
|
vin = message.text.strip().upper()
|
|
if len(vin) == 17 and vin.isalnum() and all(c not in vin for c in ["I", "O", "Q"]):
|
|
try:
|
|
make, model, year = await db.fetch_vin_info(vin)
|
|
response_text = f"🚗 **{year} {make} {model}**"
|
|
await message.answer(response_text, parse_mode="Markdown")
|
|
except Exception as e:
|
|
logging.error(f"Database error for VIN {vin}: {e}")
|
|
await message.answer("Error retrieving data from database. Please try again later.")
|
|
await state.clear()
|
|
else:
|
|
await message.answer("Invalid VIN. Please enter a valid 17-character VIN (letters and numbers, no I, O, Q).")
|
|
|
|
async def on_startup():
|
|
await oracle_db.connect()
|
|
dp.message.middleware(DbSessionMiddleware(oracle_db))
|
|
|
|
|
|
async def on_shutdown():
|
|
await oracle_db.close()
|
|
|
|
|
|
# Run the bot
|
|
async def main() -> None:
|
|
bot = Bot(token=TOKEN)
|
|
dp.startup.register(on_startup)
|
|
dp.shutdown.register(on_shutdown)
|
|
await dp.start_polling(bot)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|
|
|