Procházet zdrojové kódy

Refactor the login route for AppError.

Lee Morgan před 1 rokem
rodič
revize
0d272d5420
6 změnil soubory, kde provedl 36 přidání a 58 odebrání
  1. 1 1
      bruno/Suma/User/Create.bru
  2. 22 28
      src/controllers/user.rs
  3. 0 24
      src/http_error.rs
  4. 0 1
      src/main.rs
  5. 9 0
      src/models/user.rs
  6. 4 4
      src/routes/user.rs

+ 1 - 1
bruno/Suma/User/Create.bru

@@ -12,7 +12,7 @@ post {
 
 body:json {
   {
-    "email": "lee@leemorgan.dev",
+    "email": "lee2@leemorgan.dev",
     "password_hash": "leerobertmorgan",
     "password_salt": "leerobertmorgan"
   }

+ 22 - 28
src/controllers/user.rs

@@ -1,14 +1,13 @@
-use actix_web::{post, web, HttpResponse, Responder, http::StatusCode, cookie::Cookie};
+use actix_web::{post, web, HttpResponse, cookie::Cookie};
 use mongodb::{bson::doc, Database, Collection};
 use crate::models::user::{User, NewUserInput};
 use regex::Regex;
-use crate::http_error::http_error;
 use crate::dto;
 use crate::app_error::AppError;
 use serde_json::json;
 
 #[post("/api/user")]
-pub async fn create(
+pub async fn create_route(
     db: web::Data<Database>,
     payload: web::Json<NewUserInput>
 ) -> Result<HttpResponse, AppError> {
@@ -21,35 +20,16 @@ pub async fn create(
 }
 
 #[post("/api/user/login")]
-pub async fn login(
+pub async fn login_route(
     db: web::Data<Database>,
     payload: web::Json<dto::user::Login>
-) -> impl Responder {
+) -> Result<HttpResponse, AppError> {
     let user_collection = db.collection::<User>("users");
     let email = payload.email.to_lowercase();
-
-    let user: User = match user_collection.find_one(doc!{"email": email}, None).await {
-        Ok(Some(u)) => u,
-        Ok(None) => return http_error(StatusCode::BAD_REQUEST, "User with this email doesn't exist"),
-        Err(_) => return http_error(StatusCode::INTERNAL_SERVER_ERROR, "Unable to retrieve user data")
-    };
-
-    if user.password_hash != payload.password_hash {
-        return http_error(StatusCode::BAD_REQUEST, "Invalid credentials");
-    }
-    if user.password_salt != payload.password_salt {
-        return http_error(StatusCode::BAD_REQUEST, "Invalid credentials");
-    }
-
-    let id = user._id.unwrap().to_string();
-    let cookie = Cookie::build("user", id)
-        .path("/")
-        .http_only(true)
-        .finish();
-
-    HttpResponse::Ok()
-        .cookie(cookie)
-        .json(response_user(user))
+    let user = User::find_by_email(&user_collection, &email).await?;
+    validate_password(&user, &payload.password_hash, &payload.password_salt)?;
+    let cookie = create_user_cookie(user._id.unwrap().to_string());
+    Ok(HttpResponse::Ok().cookie(cookie).json(response_user(user)))
 }
 
 fn valid_email(email: &str) -> Result<(), AppError> {
@@ -70,6 +50,20 @@ async fn user_exists(collection: &Collection<User>, email: &str) -> Result<(), A
     }
 }
 
+fn validate_password(user: &User, hash: &str, salt: &str) -> Result<(), AppError> {
+    if user.password_hash != hash || user.password_salt != salt{
+        return Err(AppError::invalid_input("Invalid credentials"));
+    }
+    Ok(())
+}
+
+fn create_user_cookie(id: String) -> Cookie<'static> {
+    Cookie::build("user", id)
+        .path("/")
+        .http_only(true)
+        .finish()
+}
+
 fn response_user(user: User) -> dto::user::ResponseUser {
     dto::user::ResponseUser {
         id: user._id.unwrap().to_string(),

+ 0 - 24
src/http_error.rs

@@ -1,24 +0,0 @@
-use actix_web::{HttpResponse, http::StatusCode};
-use serde::Serialize;
-
-#[derive(Serialize)]
-struct Error {
-    code: u16,
-    message: String
-}
-
-#[derive(Serialize)]
-struct HttpError {
-    error: Error
-}
-
-pub fn http_error(status: StatusCode, message: &str) -> HttpResponse {
-    let body = HttpError {
-        error: Error {
-            code: status.as_u16(),
-            message: message.to_string()
-        }
-    };
-
-    HttpResponse::build(status).json(body)
-}

+ 0 - 1
src/main.rs

@@ -5,7 +5,6 @@ use mongodb::{Client, Database};
 mod routes;
 mod models;
 mod controllers;
-mod http_error;
 mod dto;
 mod app_error;
 

+ 9 - 0
src/models/user.rs

@@ -1,6 +1,7 @@
 use serde::{Serialize, Deserialize};
 use bson::{oid::ObjectId, DateTime, doc};
 use mongodb::{Collection, error::Error};
+use crate::app_error::AppError;
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct User {
@@ -32,4 +33,12 @@ impl User {
         collection.insert_one(user, None).await?;
         Ok(())
     }
+
+    pub async fn find_by_email(collection: &Collection<User>, email: &str) -> Result<User, AppError> {
+        match collection.find_one(doc!{"email": email}, None).await {
+            Ok(Some(u)) => Ok(u),
+            Ok(None) => Err(AppError::invalid_input("No user with this email address")),
+            Err(e) => Err(AppError::Database(e.into()))
+        }
+    }
 }

+ 4 - 4
src/routes/user.rs

@@ -1,10 +1,10 @@
 use actix_web::web;
 use crate::controllers::user::{
-    create,
-    login
+    create_route,
+    login_route
 };
 
 pub fn config(cfg: &mut web::ServiceConfig) {
-    cfg.service(create);
-    cfg.service(login);
+    cfg.service(create_route);
+    cfg.service(login_route);
 }