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
|
/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]
|
[package]
|
||||||
name = "pawctioneer-bot"
|
name = "pawctioneer-bot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[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
|
- **sqlx**: Compile-time checked SQL queries, async support
|
||||||
- **tokio**: Industry standard async runtime
|
- **tokio**: Industry standard async runtime
|
||||||
- **rust_decimal**: Proper decimal handling for money
|
- **rust_decimal**: Proper decimal handling for money
|
||||||
- **chrono**: Timezone-aware datetime handling
|
|
||||||
|
|
||||||
## Next Implementation Steps (Priority Order)
|
## 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() {
|
use anyhow::Result;
|
||||||
println!("Hello, world!");
|
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