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