diff options
| author | 2023-12-12 18:20:56 +0000 | |
|---|---|---|
| committer | 2023-12-12 18:20:56 +0000 | |
| commit | a587459a1817c0fc57b46df3f9c69567e1e775b7 (patch) | |
| tree | ab99c6aaa7c2b3245c83db6332e4ca54006831b3 /src | |
| parent | 370a25e5a0cbb95e2aa1cec55305b22aeaf99aa0 (diff) | |
| download | pinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.tar.gz pinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.tar.bz2 pinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.zip | |
refactor: separate model and controller
Diffstat (limited to '')
| -rw-r--r-- | src/db/mod.rs | 18 | ||||
| -rw-r--r-- | src/db/users.rs | 68 | ||||
| -rw-r--r-- | src/lib.rs | 5 | ||||
| -rw-r--r-- | src/main.rs | 5 | ||||
| -rw-r--r-- | src/routes/home.rs | 7 | ||||
| -rw-r--r-- | src/routes/login.rs | 18 | ||||
| -rw-r--r-- | src/routes/signup.rs | 16 | ||||
| -rw-r--r-- | src/routes/users.rs | 7 | ||||
| -rw-r--r-- | src/users.rs | 25 | 
9 files changed, 129 insertions, 40 deletions
| diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..f010bf8 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,18 @@ +mod users; + +use sqlx::{Pool, Postgres}; + +use self::users::Users; + +#[derive(Clone)] +pub struct Database(Pool<Postgres>); + +impl Database { +    pub fn new(pool: Pool<Postgres>) -> Self { +        Self(pool) +    } + +    pub fn users(&self) -> Users { +        Users::new(self.0.clone()) +    } +} diff --git a/src/db/users.rs b/src/db/users.rs new file mode 100644 index 0000000..0fc7c64 --- /dev/null +++ b/src/db/users.rs @@ -0,0 +1,68 @@ +use sqlx::{Pool, Postgres}; + +use crate::users::User; +use crate::Result; + +#[derive(Clone)] +pub struct Users(Pool<Postgres>); +// code code code code code code code code code code code code code code +impl Users { +    pub fn new(pool: Pool<Postgres>) -> Self { +        Self(pool) +    } + +    pub async fn create(&self, user: User) -> Result<()> { +        sqlx::query!( +            r#"insert into users (username, password, email, bio, site, privacy, admin) values ($1, $2, $3, $4, $5, $6, $7)"#, +            user.username, +            user.password, +            user.email, +            user.bio, +            user.site, +            user.privacy as _, +            user.admin +        ) +        .execute(&self.0) +        .await?; +        Ok(()) +    } + +    pub async fn read(&self, user_id: i32) -> Result<User> { +        Ok( +            sqlx::query_as!( +                User, +                "select username, password, email, bio, site, privacy as \"privacy: _\", admin from users where id = $1", +                user_id +            ) +            .fetch_one(&self.0) +            .await? +        ) +    } + +    pub async fn read_username(&self, username: &str) -> Result<User> { +        Ok( +            sqlx::query_as!( +                User, +                "select username, password, email, bio, site, privacy as \"privacy: _\", admin from users where username = $1", +                username +            ) +            .fetch_one(&self.0) +            .await? +        ) +    } + +    pub async fn get_id(&self, username: &str) -> Result<i32> { +        Ok( +            sqlx::query!("select id from users where username = $1", username) +                .fetch_one(&self.0) +                .await? +                .id, +        ) +    } + +    pub async fn read_all(&self) -> Result<Vec<User>> { +        Ok(sqlx::query_as("select * from users") +            .fetch_all(&self.0) +            .await?) +    } +} @@ -1,18 +1,17 @@  #[macro_use]  mod actix_ructe; +pub mod db;  mod error;  mod notification;  pub mod routes;  mod users; -use sqlx::{Pool, Postgres}; -  type Result<T> = std::result::Result<T, crate::error::PinussyError>;  #[derive(Clone)]  pub struct Pinussy { -    pub db: Pool<Postgres>, +    pub db: db::Database,  }  #[derive(sqlx::Type)] diff --git a/src/main.rs b/src/main.rs index 6a439ec..a488835 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use actix_web::middleware::ErrorHandlers;  use actix_web::{web, App, HttpServer};  use sqlx::postgres::PgPoolOptions; +use pinussy::db::Database;  use pinussy::routes;  use pinussy::Pinussy; @@ -19,7 +20,9 @@ async fn main() -> std::io::Result<()> {      sqlx::migrate!("./migrations").run(&pool).await.unwrap(); -    let pinussy = Pinussy { db: pool }; +    let pinussy = Pinussy { +        db: Database::new(pool), +    };      HttpServer::new(move || {          App::new() diff --git a/src/routes/home.rs b/src/routes/home.rs index 11d3a72..a43eabc 100644 --- a/src/routes/home.rs +++ b/src/routes/home.rs @@ -8,12 +8,7 @@ use crate::{Pinussy, Result};  async fn get(session: Session, state: web::Data<Pinussy>) -> Result<HttpResponse> {      let username: Option<String>;      if let Some(user_id) = session.get::<i32>("user_id")? { -        username = Some( -            sqlx::query!("select username from users where id = $1", user_id) -                .fetch_one(&state.db) -                .await? -                .username, -        ) +        username = Some(state.db.users().read(user_id).await?.username)      } else {          username = None      } diff --git a/src/routes/login.rs b/src/routes/login.rs index 33f7f69..c6cf077 100644 --- a/src/routes/login.rs +++ b/src/routes/login.rs @@ -1,9 +1,9 @@  use actix_session::Session;  use actix_web::http::header::LOCATION;  use actix_web::{get, post, web, HttpResponse}; -use bcrypt::verify;  use serde::Deserialize; +use crate::error::PinussyError;  use crate::notification::{Kind, Notification};  use crate::templates;  use crate::Pinussy; @@ -27,17 +27,11 @@ async fn post(      session: Session,      form: web::Form<LoginForm>,  ) -> Result<HttpResponse> { -    match sqlx::query!( -        "select id, password from users where username = $1", -        &form.username -    ) -    .fetch_one(&state.db) -    .await -    { +    match state.db.users().read_username(&form.username).await {          Ok(user) => { -            let password_hash: String = user.password; -            if verify(&form.password, &password_hash)? { -                session.insert("user_id", user.id)?; +            if user.verify_password(&form.password)? { +                let user_id = state.db.users().get_id(&form.username).await?; +                session.insert("user_id", user_id)?;                  return Ok(HttpResponse::SeeOther()                      .insert_header((LOCATION, "/"))                      .finish()); @@ -54,7 +48,7 @@ async fn post(                  ));              }          } -        Err(sqlx::Error::RowNotFound) => { +        Err(PinussyError::Database(sqlx::Error::RowNotFound)) => {              return Ok(HttpResponse::NotFound().body(                  render!(                      templates::login_html, diff --git a/src/routes/signup.rs b/src/routes/signup.rs index ae10201..bb1f714 100644 --- a/src/routes/signup.rs +++ b/src/routes/signup.rs @@ -1,11 +1,12 @@  use actix_web::{get, post, web, HttpResponse};  use serde::Deserialize; +use crate::error::PinussyError;  use crate::notification::{Kind as NotificationKind, Notification};  use crate::templates; +use crate::users::User;  use crate::Pinussy;  use crate::Result; -use bcrypt::{hash, DEFAULT_COST};  #[get("/signup")]  async fn get() -> HttpResponse { @@ -20,15 +21,8 @@ struct SignupForm {  #[post("/signup")]  async fn post(state: web::Data<Pinussy>, form: web::Form<SignupForm>) -> Result<HttpResponse> { -    let password_hash = hash(&form.password, DEFAULT_COST)?; -    match sqlx::query!( -        "insert into users(username, password) values ($1, $2)", -        &form.username, -        password_hash -    ) -    .execute(&state.db) -    .await -    { +    let new_user = User::new(form.username.clone(), form.password.clone())?; +    match state.db.users().create(new_user).await {          Ok(_) => {              return Ok(HttpResponse::Ok().body(                  render!( @@ -43,7 +37,7 @@ async fn post(state: web::Data<Pinussy>, form: web::Form<SignupForm>) -> Result<          }          Err(e) => {              match e { -                sqlx::Error::Database(e) => { +                PinussyError::Database(sqlx::Error::Database(e)) => {                      if e.is_unique_violation() {                          return Ok(HttpResponse::Conflict().body(                              render!( diff --git a/src/routes/users.rs b/src/routes/users.rs index 2ad9ede..eb08ade 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -6,11 +6,6 @@ use crate::{Pinussy, Result};  #[get("/users")]  async fn get(state: web::Data<Pinussy>) -> Result<HttpResponse> { -    let users: Vec<User> = sqlx::query_as("select * from users") -        .fetch_all(&state.db) -        .await -        // TODO: no unwrap -        .unwrap(); -    println!("lol"); +    let users: Vec<User> = state.db.users().read_all().await?;      Ok(HttpResponse::Ok().body(render!(templates::users_html, users).unwrap()))  } diff --git a/src/users.rs b/src/users.rs index bf41fd5..4cf9310 100644 --- a/src/users.rs +++ b/src/users.rs @@ -1,8 +1,12 @@ +use bcrypt::hash; +use bcrypt::verify; +use bcrypt::DEFAULT_COST; +  use crate::Privacy; +use crate::Result;  #[derive(sqlx::FromRow)]  pub struct User { -    pub id: i32,      pub username: String,      pub password: String,      pub email: Option<String>, @@ -11,3 +15,22 @@ pub struct User {      pub privacy: Privacy,      pub admin: bool,  } + +impl User { +    pub fn new(username: String, password: String) -> Result<Self> { +        let password_hash = hash(password, DEFAULT_COST)?; +        Ok(Self { +            username, +            password: password_hash, +            email: None, +            bio: None, +            site: None, +            privacy: Privacy::Public, +            admin: true, +        }) +    } + +    pub fn verify_password(&self, password: &str) -> Result<bool> { +        Ok(verify(password, &self.password)?) +    } +} | 
