Demo flag

This commit is contained in:
Greg Shuflin 2025-02-03 02:14:49 -08:00
parent c52295fe21
commit 85224ef1f8
3 changed files with 88 additions and 14 deletions

View File

@ -26,7 +26,11 @@ This project is packaged with Nix flakes. To install and run it:
Or run it directly: Or run it directly:
```bash ```bash
# Run with a persistent database
nix run git+https://code.everydayimshuflin.com/greg/rss-reader -- -d /path/to/database.sqlite 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 ### Development
@ -46,7 +50,19 @@ To set up a development environment:
3. Run the application: 3. Run the application:
```bash ```bash
# Run with a persistent database
cargo run -- -d rss-reader.db 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
View 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");
}

View File

@ -3,6 +3,7 @@ extern crate rocket;
use clap::Parser; use clap::Parser;
mod demo;
mod feed_utils; mod feed_utils;
mod feeds; mod feeds;
mod poll; mod poll;
@ -20,7 +21,11 @@ use user::AuthenticatedUser;
struct Args { struct Args {
/// Path to the SQLite database file /// Path to the SQLite database file
#[arg(short, long)] #[arg(short, long)]
database: String, database: Option<String>,
/// Run in demo mode with an in-memory database
#[arg(long)]
demo: bool,
} }
#[derive(Database)] #[derive(Database)]
@ -58,15 +63,21 @@ fn login() -> Template {
fn rocket() -> _ { fn rocket() -> _ {
let args = Args::parse(); 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 // Run migrations and setup demo data if needed
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
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let pool = sqlx::SqlitePool::connect(&db_url).await.unwrap(); let pool = sqlx::SqlitePool::connect(&db_url).await.unwrap();
@ -74,12 +85,13 @@ fn rocket() -> _ {
.run(&pool) .run(&pool)
.await .await
.expect("Failed to run database migrations"); .expect("Failed to run database migrations");
if args.demo {
demo::setup_demo_data(&pool).await;
}
}); });
let figment = rocket::Config::figment().merge(( let figment = rocket::Config::figment().merge(("databases.rss_data.url", db_url));
"databases.rss_data.url",
format!("sqlite:{}", args.database),
));
rocket::custom(figment) rocket::custom(figment)
.mount( .mount(