Demo flag
This commit is contained in:
parent
c52295fe21
commit
85224ef1f8
18
README.md
18
README.md
@ -26,7 +26,11 @@ This project is packaged with Nix flakes. To install and run it:
|
||||
|
||||
Or run it directly:
|
||||
```bash
|
||||
# Run with a persistent database
|
||||
nix run git+https://code.everydayimshuflin.com/greg/rss-reader -- -d /path/to/database.sqlite
|
||||
|
||||
# Or try it out in demo mode (uses in-memory database)
|
||||
nix run git+https://code.everydayimshuflin.com/greg/rss-reader -- --demo
|
||||
```
|
||||
|
||||
### Development
|
||||
@ -46,7 +50,19 @@ To set up a development environment:
|
||||
|
||||
3. Run the application:
|
||||
```bash
|
||||
# Run with a persistent database
|
||||
cargo run -- -d rss-reader.db
|
||||
|
||||
# Or try it out in demo mode (uses in-memory database)
|
||||
cargo run -- --demo
|
||||
```
|
||||
|
||||
The application will be available at `http://localhost:8000`. On first run, you'll be prompted to create an admin user.
|
||||
The application will be available at `http://localhost:8000`.
|
||||
|
||||
### Demo Mode
|
||||
|
||||
When running in demo mode (using the `--demo` flag), the application will:
|
||||
- Use an in-memory SQLite database that is cleared when the application stops
|
||||
- Create two pre-configured users:
|
||||
- Admin user: username `admin`, password `admin`
|
||||
- Regular user: username `demo`, password `demo`
|
46
src/demo.rs
Normal file
46
src/demo.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use chrono;
|
||||
use sqlx;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn setup_demo_data(pool: &sqlx::SqlitePool) {
|
||||
// Create admin user
|
||||
let admin_id = Uuid::new_v4().to_string();
|
||||
let admin_hash = bcrypt::hash("admin", bcrypt::DEFAULT_COST).unwrap();
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
)
|
||||
.bind(&admin_id)
|
||||
.bind("admin")
|
||||
.bind(&admin_hash)
|
||||
.bind(Option::<String>::None)
|
||||
.bind(Option::<String>::None)
|
||||
.bind(&now)
|
||||
.bind(true)
|
||||
.execute(pool)
|
||||
.await
|
||||
.expect("Failed to create admin user");
|
||||
|
||||
// Create demo user
|
||||
let demo_id = Uuid::new_v4().to_string();
|
||||
let demo_hash = bcrypt::hash("demo", bcrypt::DEFAULT_COST).unwrap();
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
)
|
||||
.bind(&demo_id)
|
||||
.bind("demo")
|
||||
.bind(&demo_hash)
|
||||
.bind(Option::<String>::None)
|
||||
.bind(Option::<String>::None)
|
||||
.bind(&now)
|
||||
.bind(false)
|
||||
.execute(pool)
|
||||
.await
|
||||
.expect("Failed to create demo user");
|
||||
|
||||
println!("Successfully set up demo data");
|
||||
}
|
38
src/main.rs
38
src/main.rs
@ -3,6 +3,7 @@ extern crate rocket;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
mod demo;
|
||||
mod feed_utils;
|
||||
mod feeds;
|
||||
mod poll;
|
||||
@ -20,7 +21,11 @@ use user::AuthenticatedUser;
|
||||
struct Args {
|
||||
/// Path to the SQLite database file
|
||||
#[arg(short, long)]
|
||||
database: String,
|
||||
database: Option<String>,
|
||||
|
||||
/// Run in demo mode with an in-memory database
|
||||
#[arg(long)]
|
||||
demo: bool,
|
||||
}
|
||||
|
||||
#[derive(Database)]
|
||||
@ -58,15 +63,21 @@ fn login() -> Template {
|
||||
fn rocket() -> _ {
|
||||
let args = Args::parse();
|
||||
|
||||
let db_url = format!("sqlite:{}", args.database);
|
||||
let db_url = if args.demo {
|
||||
"sqlite::memory:".to_string()
|
||||
} else {
|
||||
let database = args
|
||||
.database
|
||||
.expect("Database path is required when not in demo mode");
|
||||
// Check if database file exists, create it if it doesn't
|
||||
if !std::path::Path::new(&database).exists() {
|
||||
use std::fs::File;
|
||||
File::create(&database).expect("Failed to create database file");
|
||||
}
|
||||
format!("sqlite:{}", database)
|
||||
};
|
||||
|
||||
// Check if database file exists, create it if it doesn't
|
||||
if !std::path::Path::new(&args.database).exists() {
|
||||
use std::fs::File;
|
||||
File::create(&args.database).expect("Failed to create database file");
|
||||
}
|
||||
|
||||
// Run migrations before starting the server
|
||||
// Run migrations and setup demo data if needed
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let pool = sqlx::SqlitePool::connect(&db_url).await.unwrap();
|
||||
@ -74,12 +85,13 @@ fn rocket() -> _ {
|
||||
.run(&pool)
|
||||
.await
|
||||
.expect("Failed to run database migrations");
|
||||
|
||||
if args.demo {
|
||||
demo::setup_demo_data(&pool).await;
|
||||
}
|
||||
});
|
||||
|
||||
let figment = rocket::Config::figment().merge((
|
||||
"databases.rss_data.url",
|
||||
format!("sqlite:{}", args.database),
|
||||
));
|
||||
let figment = rocket::Config::figment().merge(("databases.rss_data.url", db_url));
|
||||
|
||||
rocket::custom(figment)
|
||||
.mount(
|
||||
|
Loading…
Reference in New Issue
Block a user