feat: rewrite user model using diesel
							parent
							
								
									18a321853a
								
							
						
					
					
						commit
						77995ebec9
					
				|  | @ -579,6 +579,7 @@ checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" | |||
| dependencies = [ | ||||
|  "diesel_derives", | ||||
|  "libsqlite3-sys", | ||||
|  "r2d2", | ||||
|  "time", | ||||
| ] | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ axum = { version = "0.8.0", features = ["macros"] } | |||
| axum-extra = { version = "0.10.0", features = ["cookie"] } | ||||
| chrono = { version = "0.4.39", features = ["serde"] } | ||||
| clap = { version = "4.5.26", features = ["derive", "env"] } | ||||
| diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] } | ||||
| diesel = { version = "2.2.6", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2"] } | ||||
| r2d2 = "0.8.10" | ||||
| r2d2_sqlite = "0.25.0" | ||||
| rand = "0.8.5" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| create table plants ( | ||||
|     id integer primary key not null, | ||||
|     id bigint primary key not null, | ||||
|     name text not null, | ||||
|     species text not null, | ||||
|     description text not null | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| create table comments ( | ||||
|     id integer primary key not null, | ||||
|     plant_id integer references plants (id), | ||||
|     id bigint primary key not null, | ||||
|     plant_id bigint not null | ||||
|         references plants (id) | ||||
|         on delete cascade, | ||||
|     comment text not null | ||||
| ); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| create table events ( | ||||
|     id integer primary key not null, | ||||
|     plant_id integer not null | ||||
|     id bigint primary key not null, | ||||
|     plant_id bigint not null | ||||
|         references plants (id) | ||||
|         on delete cascade, | ||||
|     event_type text not null, | ||||
|  |  | |||
|  | @ -1,13 +1,13 @@ | |||
| create table users ( | ||||
|     id integer primary key not null, | ||||
|     id bigint primary key not null, | ||||
|     username text unique not null, | ||||
|     password_hash text not null, | ||||
|     admin boolean not null | ||||
| ); | ||||
| 
 | ||||
| create table sessions ( | ||||
|     id integer primary key not null, | ||||
|     user_id integer not null | ||||
|     id bigint primary key not null, | ||||
|     user_id bigint not null | ||||
|         references users (id) | ||||
|         on delete cascade, | ||||
|     unique (id, user_id) | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| mod comment; | ||||
| mod event; | ||||
| mod models; | ||||
| mod plant; | ||||
| mod schema; | ||||
| mod session; | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| mod user; | ||||
|  | @ -0,0 +1,75 @@ | |||
| use argon2::{ | ||||
|     password_hash::{rand_core::OsRng, SaltString}, | ||||
|     Argon2, PasswordHash, PasswordHasher, PasswordVerifier, | ||||
| }; | ||||
| use diesel::prelude::*; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 
 | ||||
| use crate::db::schema::*; | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Clone, Queryable, Selectable)] | ||||
| #[diesel(table_name = users)] | ||||
| #[diesel(check_for_backend(diesel::sqlite::Sqlite))] | ||||
| pub struct User { | ||||
|     pub id: i64, | ||||
|     pub username: String, | ||||
|     pub password_hash: String, | ||||
|     pub admin: bool, | ||||
| } | ||||
| 
 | ||||
| #[derive(Deserialize, Insertable)] | ||||
| #[diesel(table_name = users)] | ||||
| #[diesel(check_for_backend(diesel::sqlite::Sqlite))] | ||||
| pub struct NewUser { | ||||
|     pub username: String, | ||||
|     pub password_hash: String, | ||||
|     pub admin: bool, | ||||
| } | ||||
| 
 | ||||
| fn hash_password(password: impl AsRef<str>) -> String { | ||||
|     let salt = SaltString::generate(&mut OsRng); | ||||
|     let argon2 = Argon2::default(); | ||||
| 
 | ||||
|     argon2 | ||||
|         .hash_password(password.as_ref().as_bytes(), &salt) | ||||
|         .unwrap() | ||||
|         .to_string() | ||||
| } | ||||
| 
 | ||||
| impl NewUser { | ||||
|     pub fn new(username: String, password: String, admin: bool) -> Self { | ||||
|         Self { | ||||
|             username, | ||||
|             password_hash: hash_password(&password), | ||||
|             admin, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn insert(self, conn: &mut SqliteConnection) -> QueryResult<User> { | ||||
|         diesel::insert_into(users::table) | ||||
|             .values(self) | ||||
|             .returning(User::as_returning()) | ||||
|             .get_result(conn) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl User { | ||||
|     pub fn by_username( | ||||
|         conn: &mut SqliteConnection, | ||||
|         username: impl AsRef<str>, | ||||
|     ) -> QueryResult<Option<Self>> { | ||||
|         users::dsl::users | ||||
|             .select(User::as_select()) | ||||
|             .filter(users::username.eq(username.as_ref())) | ||||
|             .first(conn) | ||||
|             .optional() | ||||
|     } | ||||
| 
 | ||||
|     pub fn verify_password(&self, password: impl AsRef<str>) -> bool { | ||||
|         let password_hash = PasswordHash::new(&self.password_hash).unwrap(); | ||||
| 
 | ||||
|         Argon2::default() | ||||
|             .verify_password(password.as_ref().as_bytes(), &password_hash) | ||||
|             .is_ok() | ||||
|     } | ||||
| } | ||||
|  | @ -2,16 +2,16 @@ | |||
| 
 | ||||
| diesel::table! { | ||||
|     comments (id) { | ||||
|         id -> Integer, | ||||
|         plant_id -> Nullable<Integer>, | ||||
|         id -> BigInt, | ||||
|         plant_id -> BigInt, | ||||
|         comment -> Text, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| diesel::table! { | ||||
|     events (id) { | ||||
|         id -> Integer, | ||||
|         plant_id -> Integer, | ||||
|         id -> BigInt, | ||||
|         plant_id -> BigInt, | ||||
|         event_type -> Text, | ||||
|         date -> Text, | ||||
|         description -> Text, | ||||
|  | @ -20,7 +20,7 @@ diesel::table! { | |||
| 
 | ||||
| diesel::table! { | ||||
|     plants (id) { | ||||
|         id -> Integer, | ||||
|         id -> BigInt, | ||||
|         name -> Text, | ||||
|         species -> Text, | ||||
|         description -> Text, | ||||
|  | @ -29,14 +29,14 @@ diesel::table! { | |||
| 
 | ||||
| diesel::table! { | ||||
|     sessions (id) { | ||||
|         id -> Integer, | ||||
|         user_id -> Integer, | ||||
|         id -> BigInt, | ||||
|         user_id -> BigInt, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| diesel::table! { | ||||
|     users (id) { | ||||
|         id -> Integer, | ||||
|         id -> BigInt, | ||||
|         username -> Text, | ||||
|         password_hash -> Text, | ||||
|         admin -> Bool, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue