add .env.example, user-stories.md
This commit is contained in:
52
.env.example
Normal file
52
.env.example
Normal file
@@ -0,0 +1,52 @@
|
||||
# ==================================
|
||||
# Pawctioneer Bot Configuration
|
||||
# ==================================
|
||||
# Copy this file to .env and fill in your values
|
||||
# Usage: cp .env.example .env
|
||||
|
||||
# ==== REQUIRED SETTINGS ====
|
||||
|
||||
# Your Telegram bot token from @BotFather
|
||||
# Get one by messaging @BotFather on Telegram and creating a new bot
|
||||
TELOXIDE_TOKEN=your_bot_token_here
|
||||
|
||||
# ==== OPTIONAL SETTINGS ====
|
||||
|
||||
# Database file location (SQLite)
|
||||
# Default: sqlite:pawctioneer_bot.db
|
||||
# You can use an absolute path: /path/to/your/database.db
|
||||
DATABASE_URL=sqlite:pawctioneer_bot.db
|
||||
|
||||
# Your Telegram user ID for admin commands
|
||||
# You can get this by messaging @userinfobot on Telegram
|
||||
# Uncomment and set your user ID to enable admin features
|
||||
# ADMIN_USER_ID=123456789
|
||||
|
||||
# Port for the web admin interface (future feature)
|
||||
# Default: 3000
|
||||
WEB_PORT=3000
|
||||
|
||||
# ==== LOGGING SETTINGS ====
|
||||
|
||||
# Logging level configuration
|
||||
# Options: error, warn, info, debug, trace
|
||||
# You can set different levels for different modules:
|
||||
# Examples:
|
||||
# RUST_LOG=info # All modules at info level
|
||||
# RUST_LOG=debug # All modules at debug level
|
||||
# RUST_LOG=info,pawctioneer_bot=debug # Most modules info, this bot debug
|
||||
# RUST_LOG=warn,teloxide=info # Most modules warn, teloxide info
|
||||
RUST_LOG=info
|
||||
|
||||
# Timezone (optional, uses system timezone if not set)
|
||||
# Examples: UTC, America/New_York, Europe/London, Asia/Tokyo
|
||||
# TZ=UTC
|
||||
|
||||
# ==== DEVELOPMENT SETTINGS ====
|
||||
# These settings are primarily for development and testing
|
||||
|
||||
# Enable more verbose teloxide logging (uncomment for debugging)
|
||||
# RUST_LOG=debug,teloxide=debug
|
||||
|
||||
# Database with more detailed logging (uncomment for SQL debugging)
|
||||
# RUST_LOG=debug,sqlx=debug
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
/target
|
||||
!.env.example
|
||||
.env
|
||||
|
||||
3570
Cargo.lock
generated
3570
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@@ -1,6 +1,21 @@
|
||||
[package]
|
||||
name = "pawctioneer-bot"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
teloxide = { version = "0.17.0", features = ["macros"] }
|
||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"chrono",
|
||||
"rust_decimal",
|
||||
] }
|
||||
rust_decimal = { version = "1.33", features = ["serde"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.11.8"
|
||||
anyhow = "1.0"
|
||||
dotenvy = "0.15"
|
||||
|
||||
@@ -245,7 +245,6 @@ settings - Configure notifications
|
||||
- **sqlx**: Compile-time checked SQL queries, async support
|
||||
- **tokio**: Industry standard async runtime
|
||||
- **rust_decimal**: Proper decimal handling for money
|
||||
- **chrono**: Timezone-aware datetime handling
|
||||
|
||||
## Next Implementation Steps (Priority Order)
|
||||
|
||||
|
||||
64
backlog/docs/user-stories.md
Normal file
64
backlog/docs/user-stories.md
Normal file
@@ -0,0 +1,64 @@
|
||||
## Types of listings:
|
||||
- Fixed price
|
||||
- Basic auction
|
||||
- Multi-slot auction
|
||||
- Blind auction
|
||||
|
||||
## User stories for listing types:
|
||||
|
||||
### Fixed price
|
||||
- As a seller,
|
||||
- I can specify a fixed price.
|
||||
- I can set a number of items / slots available for sale.
|
||||
- I can edit the number of items / slots available for sale.
|
||||
|
||||
### Basic auction
|
||||
- As a seller,
|
||||
- I can create a basic auction with a starting price.
|
||||
- I can specify the minimum price increment.
|
||||
|
||||
### Multi-slot auction
|
||||
- As a seller,
|
||||
- I can specify separate slots for an auction.
|
||||
- I can specify separate starting prices on each slot.
|
||||
- As a buyer,
|
||||
- I can submit a bid contingent on mutliple slots
|
||||
### Blind auction
|
||||
- As a seller,
|
||||
- I can specify a starting price.
|
||||
- I can see submitted bids so far.
|
||||
- I can end the auction early when I have a bid I am happy with.
|
||||
- As a buyer,
|
||||
- I can submit a bid with a price and a description.
|
||||
- I can resubmit my bid with a higher price or revised description.
|
||||
|
||||
## User stories for all listing types:
|
||||
- As a seller,
|
||||
- I can create different listing types via the Pawctionerr telegram bot.
|
||||
- I can specify photos and videos to be shown on the listing post.
|
||||
- I can edit listings by adding and removing new photos and videos.
|
||||
- I can edit listings by supplying a new description text.
|
||||
- I can mark a won / purchased listing as paid for.
|
||||
- I can view won / purchased listings by status (paid for, pending).
|
||||
|
||||
## User stories for auctions:
|
||||
- As a seller,
|
||||
- I can specify a starting date and time (or now).
|
||||
- I can specify a duration.
|
||||
- I can register for notifications when a bid is submitted.
|
||||
- I can see a list of bids submitted so far.
|
||||
- I can void bids.
|
||||
- As a buyer,
|
||||
- I can see the current high bid.
|
||||
- I cannot see the name of the high bidder unless it is me.
|
||||
- I can clearly see if I am the highest bidder.
|
||||
- I can request my bid be voided.
|
||||
|
||||
## User stories for non-blind auctions:
|
||||
- As a seller,
|
||||
- I can specify an auto-buy price.
|
||||
- I can specify an anti-sniping period.
|
||||
- As a buyer,
|
||||
- I can register for a notification when an artist starts a new auction.
|
||||
- I can register for a notification when I am outbid.
|
||||
- I can register for a notification when an auction ends.
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
id: task-001
|
||||
title: Set up database connection and SQLx integration
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Integrate SQLx with the existing configuration system to establish database connections. This includes setting up connection pooling and integrating with the Config struct.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Database connection pool is created using Config.database_url
|
||||
- [ ] #2 Connection health check function is implemented
|
||||
- [ ] #3 Database connection is properly integrated with main.rs
|
||||
- [ ] #4 Error handling for database connection failures is implemented
|
||||
<!-- AC:END -->
|
||||
21
backlog/tasks/task-002 - Create-database-migration-system.md
Normal file
21
backlog/tasks/task-002 - Create-database-migration-system.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
id: task-002
|
||||
title: Create database migration system
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Set up SQLx migrations infrastructure to manage database schema versions. Create the migrations directory structure and initial migration files.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 migrations/ directory is created with proper structure
|
||||
- [ ] #2 001_initial_schema.sql migration file contains complete schema
|
||||
- [ ] #3 Migration runner is integrated with application startup
|
||||
- [ ] #4 Database schema matches the design specified in README.md
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: task-003
|
||||
title: Create core database models and structs
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Define Rust structs and enums that represent the database schema entities. This includes User, Auction, Bid, ProxyBid, AuctionMedia, and UserSettings models with proper SQLx derive macros.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 User struct with all fields from users table is defined
|
||||
- [ ] #2 Auction struct with AuctionType enum is defined
|
||||
- [ ] #3 Bid and ProxyBid structs are defined with proper relationships
|
||||
- [ ] #4 AuctionMedia and UserSettings structs are defined
|
||||
- [ ] #5 All models have proper SQLx derive macros (FromRow, Type, etc.)
|
||||
- [ ] #6 Rust Decimal is used for monetary fields
|
||||
- [ ] #7 Chrono DateTime is used for timestamp fields
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
id: task-004
|
||||
title: Implement user management database operations
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create database operations for user registration, lookup, and management. This includes automatic user registration on first bot interaction and user preference management.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 User registration function creates new users from Telegram data
|
||||
- [ ] #2 User lookup by telegram_id function is implemented
|
||||
- [ ] #3 User settings creation with default values is implemented
|
||||
- [ ] #4 User ban/unban functionality is implemented
|
||||
- [ ] #5 User profile update functionality is implemented
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
id: task-005
|
||||
title: Implement auction database operations
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create database operations for auction management including creation, retrieval, updates, and media handling. Support all four auction types: standard, multi-slot, fixed-price, and blind auctions.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Auction creation function supports all four auction types
|
||||
- [ ] #2 Auction retrieval by ID and by seller functions are implemented
|
||||
- [ ] #3 Auction update functions (status, end time, etc.) are implemented
|
||||
- [ ] #4 Active auctions listing with pagination is implemented
|
||||
- [ ] #5 Auction media attachment functions are implemented
|
||||
- [ ] #6 Auction search and filtering functionality is implemented
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: task-006
|
||||
title: Implement bidding system database operations
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create database operations for the bidding system including manual bids, proxy bids, and bid history tracking. This is critical for the auction functionality.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Manual bid placement function with validation is implemented
|
||||
- [ ] #2 Proxy bid creation and management functions are implemented
|
||||
- [ ] #3 Bid history retrieval functions are implemented
|
||||
- [ ] #4 Winning bid calculation functions are implemented
|
||||
- [ ] #5 Multi-slot auction winner selection is implemented
|
||||
- [ ] #6 Bid cancellation functionality is implemented
|
||||
- [ ] #7 Anti-snipe time extension logic is implemented
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: task-007
|
||||
title: Create database integration tests
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Build comprehensive test suite for all database operations to ensure data integrity and proper functionality. Include edge cases and error scenarios.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 User management tests cover registration and lookup scenarios
|
||||
- [ ] #2 Auction operation tests cover all auction types
|
||||
- [ ] #3 Bidding system tests cover manual and proxy bids
|
||||
- [ ] #4 Multi-slot auction tests verify winner selection logic
|
||||
- [ ] #5 Database constraint tests verify foreign key relationships
|
||||
- [ ] #6 Error handling tests for invalid data scenarios
|
||||
- [ ] #7 Performance tests for database operations under load
|
||||
<!-- AC:END -->
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
id: task-008
|
||||
title: Integrate database with bot commands
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:31'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Connect the database operations with the existing bot command handlers to enable real functionality. Replace stub implementations with actual database-backed operations.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Start command registers new users automatically
|
||||
- [ ] #2 Settings command integrates with user_settings table
|
||||
- [ ] #3 MyAuctions command displays user's actual auctions
|
||||
- [ ] #4 MyBids command shows user's actual bid history
|
||||
- [ ] #5 Error handling for database operations in commands
|
||||
- [ ] #6 User context is properly passed to database operations
|
||||
<!-- AC:END -->
|
||||
24
backlog/tasks/task-009 - Create-database-module-structure.md
Normal file
24
backlog/tasks/task-009 - Create-database-module-structure.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
id: task-009
|
||||
title: Create database module structure
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2025-08-27 18:32'
|
||||
labels: []
|
||||
dependencies: []
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Organize database-related code into a proper module structure with separation of concerns. Create db module with sub-modules for different entity operations.
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 src/db/mod.rs module is created with proper exports
|
||||
- [ ] #2 src/db/models.rs contains all database model definitions
|
||||
- [ ] #3 src/db/users.rs contains user-related database operations
|
||||
- [ ] #4 src/db/auctions.rs contains auction-related database operations
|
||||
- [ ] #5 src/db/bids.rs contains bidding-related database operations
|
||||
- [ ] #6 src/db/connection.rs handles database connection management
|
||||
- [ ] #7 Database module is integrated with main.rs and config system
|
||||
<!-- AC:END -->
|
||||
15
src/commands/help.rs
Normal file
15
src/commands/help.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use teloxide::{prelude::*, types::Message, utils::command::BotCommands, Bot};
|
||||
|
||||
use crate::Command;
|
||||
|
||||
pub async fn handle_help(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let help_message = format!(
|
||||
"📋 Available Commands:\n\n{}\n\n\
|
||||
📧 Support: Contact @admin for help\n\
|
||||
🔗 More info: Use individual commands to get started!",
|
||||
Command::descriptions()
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, help_message).await?;
|
||||
Ok(())
|
||||
}
|
||||
14
src/commands/mod.rs
Normal file
14
src/commands/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
pub mod help;
|
||||
pub mod myauctions;
|
||||
pub mod mybids;
|
||||
pub mod newauction;
|
||||
pub mod settings;
|
||||
pub mod start;
|
||||
|
||||
// Re-export all command handlers for easy access
|
||||
pub use help::handle_help;
|
||||
pub use myauctions::handle_my_auctions;
|
||||
pub use mybids::handle_my_bids;
|
||||
pub use newauction::handle_new_auction;
|
||||
pub use settings::handle_settings;
|
||||
pub use start::handle_start;
|
||||
21
src/commands/myauctions.rs
Normal file
21
src/commands/myauctions.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, types::Message, Bot};
|
||||
|
||||
pub async fn handle_my_auctions(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let response = "📊 My Auctions (Coming Soon)\n\n\
|
||||
Here you'll be able to view and manage:\n\
|
||||
• Your active auctions\n\
|
||||
• Auction performance\n\
|
||||
• Bid history\n\
|
||||
• Winner selection (for blind auctions)\n\n\
|
||||
Feature in development! 🔧";
|
||||
|
||||
info!(
|
||||
"User {} ({}) checked their auctions",
|
||||
msg.chat.username().unwrap_or("unknown"),
|
||||
msg.chat.id
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, response).await?;
|
||||
Ok(())
|
||||
}
|
||||
21
src/commands/mybids.rs
Normal file
21
src/commands/mybids.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, types::Message, Bot};
|
||||
|
||||
pub async fn handle_my_bids(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let response = "🎯 My Bids (Coming Soon)\n\n\
|
||||
Here you'll be able to view:\n\
|
||||
• Your active bids\n\
|
||||
• Bid status (winning/outbid)\n\
|
||||
• Proxy bid settings\n\
|
||||
• Auction end times\n\n\
|
||||
Feature in development! 🏗️";
|
||||
|
||||
info!(
|
||||
"User {} ({}) checked their bids",
|
||||
msg.chat.username().unwrap_or("unknown"),
|
||||
msg.chat.id
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, response).await?;
|
||||
Ok(())
|
||||
}
|
||||
21
src/commands/newauction.rs
Normal file
21
src/commands/newauction.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, types::Message, Bot};
|
||||
|
||||
pub async fn handle_new_auction(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let response = "🏗️ New Auction Creation (Coming Soon)\n\n\
|
||||
This feature will allow you to create:\n\
|
||||
• Standard time-based auctions\n\
|
||||
• Multi-slot auctions\n\
|
||||
• Fixed price sales\n\
|
||||
• Blind auctions\n\n\
|
||||
Stay tuned! 🎪";
|
||||
|
||||
info!(
|
||||
"User {} ({}) attempted to create new auction",
|
||||
msg.chat.username().unwrap_or("unknown"),
|
||||
msg.chat.id
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, response).await?;
|
||||
Ok(())
|
||||
}
|
||||
21
src/commands/settings.rs
Normal file
21
src/commands/settings.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, types::Message, Bot};
|
||||
|
||||
pub async fn handle_settings(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let response = "⚙️ Settings (Coming Soon)\n\n\
|
||||
Here you'll be able to configure:\n\
|
||||
• Notification preferences\n\
|
||||
• Language settings\n\
|
||||
• Default bid increments\n\
|
||||
• Outbid alerts\n\n\
|
||||
Feature in development! 🛠️";
|
||||
|
||||
info!(
|
||||
"User {} ({}) accessed settings",
|
||||
msg.chat.username().unwrap_or("unknown"),
|
||||
msg.chat.id
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, response).await?;
|
||||
Ok(())
|
||||
}
|
||||
22
src/commands/start.rs
Normal file
22
src/commands/start.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, types::Message, Bot};
|
||||
|
||||
pub async fn handle_start(bot: Bot, msg: Message) -> ResponseResult<()> {
|
||||
let welcome_message = "🎯 Welcome to Pawctioneer Bot! 🎯\n\n\
|
||||
This bot helps you participate in various types of auctions:\n\
|
||||
• Standard auctions with anti-sniping protection\n\
|
||||
• Multi-slot auctions (multiple winners)\n\
|
||||
• Fixed price sales\n\
|
||||
• Blind auctions\n\n\
|
||||
Use /help to see all available commands.\n\n\
|
||||
Ready to start your auction experience? 🚀";
|
||||
|
||||
info!(
|
||||
"User {} ({}) started the bot",
|
||||
msg.chat.username().unwrap_or("unknown"),
|
||||
msg.chat.id
|
||||
);
|
||||
|
||||
bot.send_message(msg.chat.id, welcome_message).await?;
|
||||
Ok(())
|
||||
}
|
||||
84
src/config.rs
Normal file
84
src/config.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use anyhow::{Context, Result};
|
||||
use std::env;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
/// Telegram bot token (required)
|
||||
pub telegram_token: String,
|
||||
/// Database URL (required)
|
||||
pub database_url: String,
|
||||
/// Admin user ID for administrative commands
|
||||
pub admin_user_id: Option<i64>,
|
||||
/// Port for the web interface (future feature)
|
||||
pub web_port: u16,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Load and validate configuration from environment variables
|
||||
///
|
||||
/// This function expects a .env file to be present or environment variables to be set.
|
||||
/// Required variables: TELOXIDE_TOKEN
|
||||
/// Optional variables: DATABASE_URL, ADMIN_USER_ID, WEB_PORT
|
||||
///
|
||||
/// The configuration is automatically validated during construction.
|
||||
pub fn from_env() -> Result<Self> {
|
||||
// Load .env file if present (fails silently if not found)
|
||||
let _ = dotenvy::dotenv();
|
||||
|
||||
let telegram_token = env::var("TELOXIDE_TOKEN")
|
||||
.context("TELOXIDE_TOKEN environment variable is required")?;
|
||||
|
||||
let database_url =
|
||||
env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite:pawctioneer_bot.db".to_string());
|
||||
|
||||
let admin_user_id = env::var("ADMIN_USER_ID")
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<i64>().ok());
|
||||
|
||||
let web_port = env::var("WEB_PORT")
|
||||
.unwrap_or_else(|_| "3000".to_string())
|
||||
.parse::<u16>()
|
||||
.context("WEB_PORT must be a valid port number")?;
|
||||
|
||||
let config = Config {
|
||||
telegram_token,
|
||||
database_url,
|
||||
admin_user_id,
|
||||
web_port,
|
||||
};
|
||||
|
||||
// Automatically validate before returning
|
||||
config.validate()?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Internal validation method called automatically by from_env()
|
||||
///
|
||||
/// This method validates the configuration and logs important settings.
|
||||
/// It's called internally and doesn't need to be called manually.
|
||||
fn validate(&self) -> Result<()> {
|
||||
if self.telegram_token.is_empty() {
|
||||
anyhow::bail!("Telegram token cannot be empty");
|
||||
}
|
||||
|
||||
if self.database_url.is_empty() {
|
||||
anyhow::bail!("Database URL cannot be empty");
|
||||
}
|
||||
|
||||
// Log configuration (without sensitive data)
|
||||
log::info!("Configuration loaded:");
|
||||
log::info!(" Database URL: {}", self.database_url);
|
||||
log::info!(" Web Port: {}", self.web_port);
|
||||
|
||||
if let Some(admin_id) = self.admin_user_id {
|
||||
log::info!(" Admin User ID: {}", admin_id);
|
||||
} else {
|
||||
log::info!(" Admin User ID: Not set");
|
||||
}
|
||||
|
||||
log::info!(" Telegram Token: [CONFIGURED]");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
64
src/main.rs
64
src/main.rs
@@ -1,3 +1,63 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use teloxide::{prelude::*, utils::command::BotCommands};
|
||||
|
||||
mod commands;
|
||||
mod config;
|
||||
|
||||
use commands::*;
|
||||
use config::Config;
|
||||
|
||||
#[derive(BotCommands, Clone)]
|
||||
#[command(rename_rule = "lowercase", description = "Auction Bot Commands")]
|
||||
pub enum Command {
|
||||
#[command(description = "Show welcome message")]
|
||||
Start,
|
||||
#[command(description = "Show help message")]
|
||||
Help,
|
||||
#[command(description = "Create a new auction")]
|
||||
NewAuction,
|
||||
#[command(description = "View your auctions as a seller")]
|
||||
MyAuctions,
|
||||
#[command(description = "View your active bids")]
|
||||
MyBids,
|
||||
#[command(description = "Configure notifications")]
|
||||
Settings,
|
||||
}
|
||||
|
||||
// No longer needed - dptree will dispatch directly!
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Initialize logging
|
||||
env_logger::init();
|
||||
|
||||
// Load and validate configuration from environment/.env file
|
||||
let config = Config::from_env()?;
|
||||
|
||||
info!("Starting Pawctioneer Bot...");
|
||||
|
||||
let bot = Bot::new(&config.telegram_token);
|
||||
|
||||
// Create dispatcher with direct command routing
|
||||
Dispatcher::builder(
|
||||
bot,
|
||||
Update::filter_message().branch(
|
||||
dptree::entry()
|
||||
.filter_command::<Command>()
|
||||
.branch(dptree::case![Command::Start].endpoint(handle_start))
|
||||
.branch(dptree::case![Command::Help].endpoint(handle_help))
|
||||
.branch(dptree::case![Command::NewAuction].endpoint(handle_new_auction))
|
||||
.branch(dptree::case![Command::MyAuctions].endpoint(handle_my_auctions))
|
||||
.branch(dptree::case![Command::MyBids].endpoint(handle_my_bids))
|
||||
.branch(dptree::case![Command::Settings].endpoint(handle_settings)),
|
||||
),
|
||||
)
|
||||
.dependencies(dptree::deps![])
|
||||
.enable_ctrlc_handler()
|
||||
.build()
|
||||
.dispatch()
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user