Ready for a database
This commit is contained in:
parent
bfc5a6f90d
commit
0782e82d6e
15 changed files with 75 additions and 368 deletions
214
Cargo.lock
generated
214
Cargo.lock
generated
|
@ -358,49 +358,6 @@ dependencies = [
|
|||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deadpool-runtime",
|
||||
"num_cpus",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool-diesel"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa8404d25ddc6cb0676d4a863bbd007613ee3fffb54db23e0e6341e1fe61c3e"
|
||||
dependencies = [
|
||||
"deadpool",
|
||||
"deadpool-sync",
|
||||
"diesel",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool-runtime"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49"
|
||||
dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deadpool-sync"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8db70494c13cae4ce67b4b4dafdaf828cf0df7237ab5b9e2fcabee4965d0a0a"
|
||||
dependencies = [
|
||||
"deadpool-runtime",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.9"
|
||||
|
@ -410,50 +367,6 @@ dependencies = [
|
|||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33"
|
||||
dependencies = [
|
||||
"diesel_derives",
|
||||
"libsqlite3-sys",
|
||||
"time",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_derives"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44"
|
||||
dependencies = [
|
||||
"diesel_table_macro_syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_migrations"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"migrations_internals",
|
||||
"migrations_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_table_macro_syntax"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
|
||||
dependencies = [
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
|
@ -465,12 +378,6 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
|
@ -593,12 +500,6 @@ version = "0.28.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.3.9"
|
||||
|
@ -713,16 +614,6 @@ version = "0.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.9.6"
|
||||
|
@ -790,16 +681,6 @@ version = "0.2.150"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
|
@ -828,10 +709,6 @@ dependencies = [
|
|||
"base64",
|
||||
"color-eyre",
|
||||
"cookie",
|
||||
"deadpool",
|
||||
"deadpool-diesel",
|
||||
"diesel",
|
||||
"diesel_migrations",
|
||||
"maud",
|
||||
"notify",
|
||||
"serde",
|
||||
|
@ -886,27 +763,6 @@ version = "2.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "migrations_internals"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "migrations_macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08"
|
||||
dependencies = [
|
||||
"migrations_internals",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
|
@ -1088,12 +944,6 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.1"
|
||||
|
@ -1326,15 +1176,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -1549,40 +1390,6 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
@ -1759,24 +1566,12 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -1904,12 +1699,3 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
@ -20,12 +20,6 @@ tower-http = { version = "0.4.4", features = ["fs"] }
|
|||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
|
||||
# database
|
||||
deadpool = "0.10.0"
|
||||
deadpool-diesel = { version = "0.5.0", features = ["rt_tokio_1", "sqlite", "tracing", "serde"] }
|
||||
diesel = { version = "2.1.3", features = ["sqlite", "uuid"] }
|
||||
diesel_migrations = { version = "2.1.0", features = ["sqlite"] }
|
||||
|
||||
# fancy during-development stuff
|
||||
notify = "6.1.1"
|
||||
tower-livereload = "0.8.2"
|
||||
|
@ -34,7 +28,6 @@ thiserror = "1.0.50"
|
|||
axum-macros = "0.3.8"
|
||||
color-eyre = "0.6.2"
|
||||
|
||||
# color-eyre
|
||||
# irust
|
||||
# bacon
|
||||
# sqlx (sea orm?)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
custom_type_derives = ["diesel::query_builder::QueryId"]
|
||||
|
||||
[migrations_directory]
|
||||
dir = "migrations"
|
|
@ -50,11 +50,9 @@
|
|||
|
||||
rustfmt
|
||||
rustPackages.clippy
|
||||
rustPackages.bacon
|
||||
rust-analyzer
|
||||
nodePackages_latest.vscode-langservers-extracted
|
||||
|
||||
diesel-cli
|
||||
hurl
|
||||
];
|
||||
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
drop table users
|
|
@ -1,7 +0,0 @@
|
|||
create table users (
|
||||
id text primary key,
|
||||
username text
|
||||
name text,
|
||||
password_digest binary
|
||||
);
|
||||
create unique index users_username on users(username);
|
|
@ -1,42 +1 @@
|
|||
use deadpool_diesel::sqlite::{Manager, Pool, Runtime};
|
||||
use diesel::sqlite::Sqlite;
|
||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Database {
|
||||
pub pool: Pool,
|
||||
}
|
||||
|
||||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
|
||||
|
||||
impl Database {
|
||||
// TODO: database seeding?
|
||||
|
||||
fn run_migrations(
|
||||
connection: &mut impl MigrationHarness<Sqlite>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
// This will run the necessary migrations.
|
||||
//
|
||||
// See the documentation for `MigrationHarness` for
|
||||
// all available methods.
|
||||
connection.run_pending_migrations(MIGRATIONS)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: make an actual error type
|
||||
pub async fn new<T: AsRef<str>>(database_url: T) -> Result<Self, anyhow::Error> {
|
||||
let manager = Manager::new(database_url.as_ref(), Runtime::Tokio1);
|
||||
let pool = Pool::builder(manager).max_size(8).build().unwrap();
|
||||
|
||||
let conn = pool.get().await?;
|
||||
let _ = conn
|
||||
.interact(|c| Self::run_migrations(c))
|
||||
.await
|
||||
.expect("Failed to run migrations");
|
||||
info!("Migrations completed!");
|
||||
|
||||
return Ok(Database { pool });
|
||||
}
|
||||
}
|
||||
|
|
15
src/error.rs
15
src/error.rs
|
@ -1,13 +1,9 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use axum::{
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub struct AppError(#[from] anyhow::Error);
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
|
@ -19,8 +15,11 @@ impl IntoResponse for AppError {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for AppError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format!("app error"))
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use tracing::{instrument, trace};
|
|||
use tracing_subscriber::{filter::LevelFilter, EnvFilter};
|
||||
|
||||
pub fn init() {
|
||||
color_eyre::install();
|
||||
color_eyre::install().expect("Failed to install color_eyre");
|
||||
setup_trace_logger();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ mod instrumentation;
|
|||
mod models;
|
||||
mod partials;
|
||||
mod router;
|
||||
mod schema;
|
||||
mod server;
|
||||
mod state;
|
||||
mod views;
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = crate::schema::users)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct User {
|
||||
// pub id: Text,
|
||||
// pub username: sql_types::Text,
|
||||
// pub name: sql_types::Text,
|
||||
// pub password_digest: sql_types::Binary,
|
||||
pub id: Vec<u8>,
|
||||
pub username: String,
|
||||
pub name: Option<String>,
|
||||
pub password_digest: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = crate::schema::users)]
|
||||
pub struct NewUser<'a> {
|
||||
pub username: &'a str,
|
||||
pub name: Option<&'a str>,
|
||||
pub password_digest: &'a [u8],
|
||||
pub password_digest: Vec<u8>,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{env, path::Path, sync::Arc};
|
||||
use std::{env, path::Path};
|
||||
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
|
@ -29,7 +29,7 @@ pub async fn new() -> Result<Router, anyhow::Error> {
|
|||
.route("/hello-world-text", get(views::greet_world_text));
|
||||
|
||||
let assets_dir = ServeDir::new("./assets");
|
||||
let state = Arc::new(State::new().await?);
|
||||
let state = State::new().await?;
|
||||
|
||||
let live_reload_layer = LiveReloadLayer::new();
|
||||
let reloader = live_reload_layer.reloader();
|
||||
|
@ -48,6 +48,7 @@ pub async fn new() -> Result<Router, anyhow::Error> {
|
|||
.nest("/app", app_router)
|
||||
.nest_service("/assets", assets_dir)
|
||||
.route("/", get(views::index))
|
||||
.route("/login", get(views::login).post(login))
|
||||
.route("/register", get(views::register).post(register))
|
||||
.route("/all_users", get(views::all_users))
|
||||
.with_state(state)
|
||||
|
@ -64,11 +65,23 @@ struct Register {
|
|||
password: String,
|
||||
}
|
||||
|
||||
impl<'a> TryInto<NewUser<'a>> for Register {
|
||||
type Error = ();
|
||||
impl<'a> TryInto<NewUser<'a>> for &'a Register {
|
||||
type Error = argon2::password_hash::Error;
|
||||
|
||||
fn try_into(self) -> Result<NewUser<'a>, Self::Error> {
|
||||
todo!()
|
||||
fn try_into(self: &'a Register) -> Result<NewUser<'a>, Self::Error> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
let password_digest: Vec<u8> = argon2
|
||||
.hash_password(self.password.as_bytes(), &salt)?
|
||||
.hash
|
||||
.expect("no password hash")
|
||||
.as_bytes()
|
||||
.into();
|
||||
Ok(NewUser {
|
||||
username: &self.username,
|
||||
name: None,
|
||||
password_digest,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +91,40 @@ async fn register(
|
|||
) -> Result<impl IntoResponse, AppError> {
|
||||
// TODO: https://docs.rs/axum_csrf/latest/axum_csrf/#prevent-post-replay-attacks-with-csrf
|
||||
|
||||
let v = csrf_token.verify(®ister.authenticity_token);
|
||||
if v.is_err() {
|
||||
return Ok((
|
||||
StatusCode::BAD_REQUEST,
|
||||
Html(html! { "invalid request" }.into_string()),
|
||||
));
|
||||
}
|
||||
|
||||
let new_user: NewUser = (®ister).try_into()?;
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Html(
|
||||
html! {
|
||||
h1 { (new_user.username) }
|
||||
}
|
||||
.into_string(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Login {
|
||||
authenticity_token: String,
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
async fn login(
|
||||
csrf_token: CsrfToken,
|
||||
Form(register): Form<Login>,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
// TODO: https://docs.rs/axum_csrf/latest/axum_csrf/#prevent-post-replay-attacks-with-csrf
|
||||
|
||||
let v = csrf_token.verify(®ister.authenticity_token);
|
||||
println!("{:?} {:?}", register.authenticity_token, v);
|
||||
if v.is_err() {
|
||||
|
@ -87,16 +134,6 @@ async fn register(
|
|||
));
|
||||
}
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
let password_digest = argon2.hash_password(register.password.as_bytes(), &salt)?;
|
||||
|
||||
let _new_user = NewUser {
|
||||
username: ®ister.username,
|
||||
name: None,
|
||||
password_digest: password_digest.to_string().as_bytes(),
|
||||
};
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Html(
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
users (id) {
|
||||
id -> Binary,
|
||||
username -> Text,
|
||||
name -> Nullable<Text>,
|
||||
password_digest -> Binary,
|
||||
}
|
||||
}
|
11
src/state.rs
11
src/state.rs
|
@ -1,17 +1,12 @@
|
|||
use std::env;
|
||||
|
||||
use crate::database;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
pub database: database::Database,
|
||||
}
|
||||
pub struct State {}
|
||||
|
||||
impl State {
|
||||
pub async fn new() -> Result<Self, anyhow::Error> {
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
let database = database::Database::new(database_url).await?;
|
||||
let _database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
|
||||
Ok(State { database })
|
||||
Ok(State {})
|
||||
}
|
||||
}
|
||||
|
|
44
src/views.rs
44
src/views.rs
|
@ -1,15 +1,9 @@
|
|||
use std::{error::Error, sync::Arc};
|
||||
|
||||
use axum::{
|
||||
extract::State,
|
||||
response::{Html, IntoResponse},
|
||||
};
|
||||
use axum_csrf::CsrfToken;
|
||||
use axum_macros::debug_handler;
|
||||
use deadpool_diesel::InteractError;
|
||||
use diesel::{QueryDsl, RunQueryDsl, SelectableHelper};
|
||||
use maud::html;
|
||||
use thiserror::Error;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{
|
||||
|
@ -102,32 +96,11 @@ pub async fn login(csrf: CsrfToken) -> impl IntoResponse {
|
|||
.into_response()
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum AllUsersError {
|
||||
#[error("other application error")]
|
||||
App(#[from] AppError),
|
||||
#[error("failed to retrieve users")]
|
||||
DB(#[from] InteractError),
|
||||
}
|
||||
|
||||
#[debug_handler]
|
||||
#[allow(unreachable_code)]
|
||||
pub async fn all_users(
|
||||
State(state): State<crate::state::State>,
|
||||
) -> Result<Html<String>, AllUsersError> {
|
||||
use crate::schema::users::dsl::*;
|
||||
|
||||
let conn = state.database.pool.get().await?;
|
||||
let cc = |c| -> Vec<User> {
|
||||
users
|
||||
.select(User::as_select())
|
||||
.load(c)
|
||||
.expect("error loading users")
|
||||
};
|
||||
|
||||
let all_users: Vec<User> = match conn.interact(cc).await {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Err(("failed to retrieve users")),
|
||||
};
|
||||
State(_state): State<crate::state::State>,
|
||||
) -> Result<Html<String>, AppError> {
|
||||
let all_users: Vec<User> = vec![];
|
||||
|
||||
// @if let Some(name) = u.name {
|
||||
// name
|
||||
|
@ -142,9 +115,12 @@ pub async fn all_users(
|
|||
ul {
|
||||
@for u in all_users {
|
||||
li {
|
||||
(u)
|
||||
"("
|
||||
")"
|
||||
(u.username)
|
||||
@if let Some(name) = u.name {
|
||||
" ("
|
||||
(name)
|
||||
")"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue