summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2023-12-12 18:20:56 +0000
committerLibravatar cel 🌸 <cel@blos.sm>2023-12-12 18:20:56 +0000
commita587459a1817c0fc57b46df3f9c69567e1e775b7 (patch)
treeab99c6aaa7c2b3245c83db6332e4ca54006831b3 /src
parent370a25e5a0cbb95e2aa1cec55305b22aeaf99aa0 (diff)
downloadpinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.tar.gz
pinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.tar.bz2
pinussy-a587459a1817c0fc57b46df3f9c69567e1e775b7.zip
refactor: separate model and controller
Diffstat (limited to '')
-rw-r--r--src/db/mod.rs18
-rw-r--r--src/db/users.rs68
-rw-r--r--src/lib.rs5
-rw-r--r--src/main.rs5
-rw-r--r--src/routes/home.rs7
-rw-r--r--src/routes/login.rs18
-rw-r--r--src/routes/signup.rs16
-rw-r--r--src/routes/users.rs7
-rw-r--r--src/users.rs25
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?)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 591d0c6..2105040 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)?)
+ }
+}