feat: rewrite user model using diesel
parent
18a321853a
commit
77995ebec9
|
@ -579,6 +579,7 @@ checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel_derives",
|
"diesel_derives",
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
|
"r2d2",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ axum = { version = "0.8.0", features = ["macros"] }
|
||||||
axum-extra = { version = "0.10.0", features = ["cookie"] }
|
axum-extra = { version = "0.10.0", features = ["cookie"] }
|
||||||
chrono = { version = "0.4.39", features = ["serde"] }
|
chrono = { version = "0.4.39", features = ["serde"] }
|
||||||
clap = { version = "4.5.26", features = ["derive", "env"] }
|
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 = "0.8.10"
|
||||||
r2d2_sqlite = "0.25.0"
|
r2d2_sqlite = "0.25.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
create table plants (
|
create table plants (
|
||||||
id integer primary key not null,
|
id bigint primary key not null,
|
||||||
name text not null,
|
name text not null,
|
||||||
species text not null,
|
species text not null,
|
||||||
description text not null
|
description text not null
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
create table comments (
|
create table comments (
|
||||||
id integer primary key not null,
|
id bigint primary key not null,
|
||||||
plant_id integer references plants (id),
|
plant_id bigint not null
|
||||||
|
references plants (id)
|
||||||
|
on delete cascade,
|
||||||
comment text not null
|
comment text not null
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
create table events (
|
create table events (
|
||||||
id integer primary key not null,
|
id bigint primary key not null,
|
||||||
plant_id integer not null
|
plant_id bigint not null
|
||||||
references plants (id)
|
references plants (id)
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
event_type text not null,
|
event_type text not null,
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
create table users (
|
create table users (
|
||||||
id integer primary key not null,
|
id bigint primary key not null,
|
||||||
username text unique not null,
|
username text unique not null,
|
||||||
password_hash text not null,
|
password_hash text not null,
|
||||||
admin boolean not null
|
admin boolean not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table sessions (
|
create table sessions (
|
||||||
id integer primary key not null,
|
id bigint primary key not null,
|
||||||
user_id integer not null
|
user_id bigint not null
|
||||||
references users (id)
|
references users (id)
|
||||||
on delete cascade,
|
on delete cascade,
|
||||||
unique (id, user_id)
|
unique (id, user_id)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod comment;
|
mod comment;
|
||||||
mod event;
|
mod event;
|
||||||
|
mod models;
|
||||||
mod plant;
|
mod plant;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod session;
|
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! {
|
diesel::table! {
|
||||||
comments (id) {
|
comments (id) {
|
||||||
id -> Integer,
|
id -> BigInt,
|
||||||
plant_id -> Nullable<Integer>,
|
plant_id -> BigInt,
|
||||||
comment -> Text,
|
comment -> Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
events (id) {
|
events (id) {
|
||||||
id -> Integer,
|
id -> BigInt,
|
||||||
plant_id -> Integer,
|
plant_id -> BigInt,
|
||||||
event_type -> Text,
|
event_type -> Text,
|
||||||
date -> Text,
|
date -> Text,
|
||||||
description -> Text,
|
description -> Text,
|
||||||
|
@ -20,7 +20,7 @@ diesel::table! {
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
plants (id) {
|
plants (id) {
|
||||||
id -> Integer,
|
id -> BigInt,
|
||||||
name -> Text,
|
name -> Text,
|
||||||
species -> Text,
|
species -> Text,
|
||||||
description -> Text,
|
description -> Text,
|
||||||
|
@ -29,14 +29,14 @@ diesel::table! {
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
sessions (id) {
|
sessions (id) {
|
||||||
id -> Integer,
|
id -> BigInt,
|
||||||
user_id -> Integer,
|
user_id -> BigInt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
users (id) {
|
users (id) {
|
||||||
id -> Integer,
|
id -> BigInt,
|
||||||
username -> Text,
|
username -> Text,
|
||||||
password_hash -> Text,
|
password_hash -> Text,
|
||||||
admin -> Bool,
|
admin -> Bool,
|
||||||
|
|
Loading…
Reference in New Issue