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())