diff --git a/src/db/event.rs b/src/db/event.rs deleted file mode 100644 index 2c9128a..0000000 --- a/src/db/event.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::{fmt::Display, str::FromStr}; - -use chrono::NaiveDate; -use r2d2_sqlite::rusqlite::{ - self, - types::{FromSql, FromSqlError}, - Row, ToSql, -}; -use serde::{Deserialize, Serialize}; - -use super::{DbError, DbPool}; - -pub const EVENT_TYPES: [&str; 1] = ["Watering"]; - -#[derive(Serialize, Deserialize)] -pub enum EventType { - Watering, -} - -impl ToString for EventType { - fn to_string(&self) -> String { - String::from(match self { - Self::Watering => "watering", - }) - } -} - -#[derive(Debug)] -pub struct ParseEventTypeErr; - -impl Display for ParseEventTypeErr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "invalid name") - } -} - -impl std::error::Error for ParseEventTypeErr {} - -impl FromStr for EventType { - type Err = ParseEventTypeErr; - - fn from_str(s: &str) -> Result { - match s { - "watering" => Ok(Self::Watering), - _ => Err(ParseEventTypeErr), - } - } -} - -impl ToSql for EventType { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -impl FromSql for EventType { - fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult { - value - .as_str()? - .parse() - .map_err(|e| FromSqlError::Other(Box::new(e))) - } -} - -#[derive(Serialize)] -pub struct Event { - id: i64, - plant_id: i64, - event_type: EventType, - date: NaiveDate, - description: String, -} - -impl Event { - pub fn from_row(row: &Row<'_>) -> Result { - Ok(Self { - id: row.get("id")?, - plant_id: row.get("plant_id")?, - event_type: row.get("event_type")?, - date: row.get("date")?, - description: row.get("description")?, - }) - } -} - -#[derive(Deserialize)] -pub struct NewEvent { - plant_id: i64, - event_type: EventType, - date: NaiveDate, - description: String, -} - -impl NewEvent { - pub fn insert(self, pool: &DbPool) -> Result { - let conn = pool.get()?; - - let mut stmt = conn.prepare( - "insert into events (plant_id, event_type, date, description) values ($1, $2, $3, $4) returning *", - )?; - - Ok(stmt.query_row( - ( - &self.plant_id, - &self.event_type, - &self.date, - &self.description, - ), - Event::from_row, - )?) - } -} diff --git a/src/db/mod.rs b/src/db/mod.rs index c224b9b..4991cad 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -2,21 +2,19 @@ mod models; mod schema; use diesel::{ - prelude::*, - r2d2::{ConnectionManager, Pool, PooledConnection}, + r2d2::{ConnectionManager, Pool}, SqliteConnection, }; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use std::{error::Error, fmt, path::Path}; -pub use models::event::{Event, EventType, NewEvent, EVENT_TYPES}; +pub use models::event::{Event, NewEvent, EVENT_TYPES}; pub use models::plant::{NewPlant, Plant}; pub use models::session::Session; pub use models::user::{NewUser, User}; pub type DbPool = Pool>; -pub type DbConn = PooledConnection>; pub type DbResult = Result; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); diff --git a/src/db/models/user.rs b/src/db/models/user.rs index d581fc7..fcdc7cb 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -5,7 +5,7 @@ use argon2::{ use diesel::prelude::*; use serde::{Deserialize, Serialize}; -use crate::db::{schema::*, DbConn, DbPool, DbResult}; +use crate::db::{schema::*, DbPool, DbResult}; #[derive(Serialize, Deserialize, Clone, Queryable, Selectable)] #[diesel(table_name = users)] diff --git a/src/db/plant.rs b/src/db/plant.rs deleted file mode 100644 index 1ee9f75..0000000 --- a/src/db/plant.rs +++ /dev/null @@ -1,73 +0,0 @@ -use r2d2_sqlite::rusqlite::{self, Row}; -use serde::{Deserialize, Serialize}; - -use super::{DbError, DbPool, Event}; - -#[derive(Serialize)] -pub struct Plant { - id: i64, - name: String, - species: String, - description: String, -} - -#[derive(Deserialize)] -pub struct NewPlant { - name: String, - species: String, - description: String, -} - -impl Plant { - pub fn from_row(row: &Row<'_>) -> Result { - Ok(Self { - id: row.get(0)?, - name: row.get(1)?, - species: row.get(2)?, - description: row.get(3)?, - }) - } - - pub fn all(pool: &DbPool) -> Result, DbError> { - let conn = pool.get()?; - - let mut stmt = conn.prepare("select * from plants")?; - let plants: Result, _> = stmt.query_map((), Self::from_row)?.collect(); - - Ok(plants?) - } - - pub fn by_id(pool: &DbPool, id: i64) -> Result, DbError> { - let conn = pool.get()?; - - let mut stmt = conn.prepare("select * from plants where id = $1")?; - match stmt.query_row((id,), |row| Plant::from_row(row)) { - Ok(plant) => Ok(Some(plant)), - Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), - Err(err) => Err(DbError::Db(err)), - } - } - - pub fn events(&self, pool: &DbPool) -> Result, DbError> { - let conn = pool.get()?; - let mut stmt = conn.prepare("select * from events where plant_id = $1")?; - - let events: Result, _> = stmt.query_map((self.id,), Event::from_row)?.collect(); - Ok(events?) - } -} - -impl NewPlant { - pub fn insert(self, pool: &DbPool) -> Result { - let conn = pool.get()?; - - let mut stmt = conn.prepare( - "insert into plants (name, species, description) values ($1, $2, $3) returning *", - )?; - - Ok(stmt.query_row( - (&self.name, &self.species, &self.description), - Plant::from_row, - )?) - } -} diff --git a/src/db/session.rs b/src/db/session.rs deleted file mode 100644 index 76ee09d..0000000 --- a/src/db/session.rs +++ /dev/null @@ -1,39 +0,0 @@ -use rand::Rng; -use rusqlite::Row; - -use super::{DbError, DbPool, User}; - -pub struct Session { - pub id: i64, - pub user_id: i32, -} - -impl Session { - pub fn from_row(row: &Row<'_>) -> Result { - Ok(Self { - id: row.get("id")?, - user_id: row.get("user_id")?, - }) - } - - pub fn user_from_id(pool: &DbPool, id: i64) -> Result, DbError> { - let conn = pool.get()?; - - let mut stmt = conn.prepare("select users.* from sessions inner join users on sessions.user_id = users.id where sessions.id = $1")?; - match stmt.query_row((id,), User::from_row) { - Ok(user) => Ok(Some(user)), - Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), - Err(err) => Err(DbError::Db(err)), - } - } - - pub fn new_for_user(pool: &DbPool, user_id: i64) -> Result { - let id: i64 = rand::thread_rng().gen(); - - let conn = pool.get()?; - let mut stmt = - conn.prepare("insert into sessions (id, user_id) values ($1, $2) returning *")?; - - Ok(stmt.query_row((&id, &user_id), Self::from_row)?) - } -} diff --git a/src/db/user.rs b/src/db/user.rs deleted file mode 100644 index 47ae42e..0000000 --- a/src/db/user.rs +++ /dev/null @@ -1,94 +0,0 @@ -use argon2::{ - password_hash::{rand_core::OsRng, SaltString}, - Argon2, PasswordHash, PasswordHasher, PasswordVerifier, -}; -use rusqlite::Row; -use serde::{Deserialize, Serialize}; - -use super::{DbError, DbPool}; - -#[derive(Serialize, Deserialize, Clone)] -pub struct User { - pub id: i64, - pub username: String, - pub password_hash: String, - pub admin: bool, -} - -#[derive(Serialize, Deserialize)] -pub struct NewUser { - pub username: String, - pub password: String, - pub admin: bool, -} - -impl User { - pub fn from_row(row: &Row<'_>) -> Result { - Ok(Self { - id: row.get("id")?, - username: row.get("username")?, - password_hash: row.get("password_hash")?, - admin: row.get("admin")?, - }) - } - - pub fn by_username(pool: &DbPool, username: impl AsRef) -> Result, DbError> { - let conn = pool.get()?; - - let mut stmt = conn.prepare("select * from users where username = $1")?; - - match stmt.query_row((username.as_ref(),), User::from_row) { - Ok(user) => Ok(Some(user)), - Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), - Err(err) => Err(DbError::Db(err)), - } - } - - pub fn verify_password(&self, password: impl AsRef) -> bool { - let password_hash = PasswordHash::new(&self.password_hash).unwrap(); - - Argon2::default() - .verify_password(password.as_ref().as_bytes(), &password_hash) - .is_ok() - } - - pub fn all(pool: &DbPool) -> Result, DbError> { - let conn = pool.get()?; - - let mut stmt = conn.prepare("select * from users")?; - let users: Result, _> = stmt.query_map((), Self::from_row)?.collect(); - - Ok(users?) - } - - pub fn remove_by_username(pool: &DbPool, username: impl AsRef) -> Result { - let conn = pool.get()?; - let mut stmt = conn.prepare("delete from users where username = $1")?; - - Ok(stmt.execute((username.as_ref(),))? > 0) - } -} - -fn hash_password(password: impl AsRef) -> 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 insert(self, pool: &DbPool) -> Result { - let conn = pool.get()?; - - let password_hash = hash_password(&self.password); - - let mut stmt = conn.prepare( - "insert into users (username, password_hash, admin) values ($1, $2, $3) returning *", - )?; - - Ok(stmt.query_row((&self.username, password_hash, &self.admin), User::from_row)?) - } -} diff --git a/src/main.rs b/src/main.rs index e126c83..f1d0530 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,6 @@ mod server; use std::{fs, path::Path, sync::Arc}; use clap::Parser; -use diesel_migrations::{embed_migrations, EmbeddedMigrations}; use tera::Tera; use tower_http::compression::CompressionLayer; diff --git a/src/server/auth.rs b/src/server/auth.rs index 7870650..9afbdb1 100644 --- a/src/server/auth.rs +++ b/src/server/auth.rs @@ -3,7 +3,7 @@ use axum::{ http::{HeaderMap, StatusCode}, middleware::Next, response::{Html, IntoResponse, Response}, - routing::{get, post}, + routing::post, Form, Router, }; use axum_extra::extract::{ @@ -11,11 +11,10 @@ use axum_extra::extract::{ CookieJar, }; use serde::Deserialize; -use tera::Context; use crate::db::{DbError, DbPool, Session, User}; -use super::{error::AppError, render_view}; +use super::error::AppError; pub fn logged_in_user(pool: &DbPool, headers: &HeaderMap) -> Result, DbError> { let jar = CookieJar::from_headers(headers);