Просмотр исходного кода

Create update route for transactions.

Lee Morgan 1 год назад
Родитель
Сommit
3edb44cffa

+ 11 - 0
bruno/Suma/Transaction/Update.bru

@@ -0,0 +1,11 @@
+meta {
+  name: Update
+  type: http
+  seq: 4
+}
+
+put {
+  url: http://localhost:8000/api/transaction
+  body: none
+  auth: inherit
+}

+ 29 - 2
src/controllers/transaction.rs

@@ -1,4 +1,4 @@
-use actix_web::{post, web, HttpResponse, HttpRequest};
+use actix_web::{web, post, put, HttpResponse, HttpRequest};
 use mongodb::Database;
 use bson::oid::ObjectId;
 
@@ -6,7 +6,7 @@ use crate::models::transaction::{Transaction, ResponseTransaction};
 use crate::models::account::Account;
 use crate::app_error::AppError;
 use crate::auth::user_auth;
-use crate::dto::transaction::{CreateInput, SearchInput};
+use crate::dto::transaction::{CreateInput, SearchInput, UpdateInput};
 
 #[post("/api/transaction")]
 pub async fn create_route(
@@ -51,3 +51,30 @@ pub async fn get_many_route(
 
     Ok(HttpResponse::Ok().json(response_transactions))
 }
+
+#[put("/api/transaction")]
+pub async fn update_route(
+    db: web::Data<Database>,
+    body: web::Json<UpdateInput>,
+    request: HttpRequest
+) -> Result<HttpResponse, AppError> {
+    let user = user_auth(&db, &request).await?;
+
+    let transaction_collection = db.collection::<Transaction>("transactions");
+
+    Transaction::user_owns(
+        &transaction_collection,
+        &db.collection::<Account>("accounts"),
+        ObjectId::parse_str(&body.id)?,
+        user
+    ).await?;
+
+    let transaction = Transaction::update(
+        &transaction_collection,
+        ObjectId::parse_str(&body.id)?,
+        body.data.clone(),
+        body.date.clone()
+    ).await?;
+
+    Ok(HttpResponse::Ok().json(transaction.response()))
+}

+ 7 - 0
src/dto/transaction.rs

@@ -13,3 +13,10 @@ pub struct SearchInput {
     pub from: Option<String>,
     pub to: Option<String>
 }
+
+#[derive(Deserialize)]
+pub struct UpdateInput {
+    pub id: String,
+    pub data: Option<String>,
+    pub date: Option<String>
+}

+ 54 - 1
src/models/transaction.rs

@@ -1,10 +1,12 @@
 use serde::{Serialize, Deserialize};
-use mongodb::Collection;
+use mongodb::{Collection, options::ReturnDocument};
 use bson::{doc, Document, oid::ObjectId};
 use futures::stream::TryStreamExt;
 
 use crate::app_error::AppError;
 use crate::dto::transaction::CreateInput;
+use crate::models::account::Account;
+use crate::models::user::User;
 
 #[derive(Serialize, Deserialize)]
 pub struct Transaction {
@@ -67,6 +69,57 @@ impl Transaction {
             .await?)
     }
 
+    pub async fn user_owns(
+        transaction_collection: &Collection<Transaction>,
+        account_collection: &Collection<Account>,
+        id: ObjectId,
+        user: User
+    ) -> Result<(), AppError> {
+        let transaction = match transaction_collection.find_one(doc!{"_id": id}).await {
+            Ok(Some(t)) => t,
+            Ok(None) => return Err(AppError::InvalidInput("Transaction with this ID doesn't exist".to_string())),
+            Err(e) => return Err(AppError::Database(e.into()))
+        };
+
+        let account = match account_collection.find_one(doc!{"_id": transaction.account}).await {
+            Ok(Some(a)) => a,
+            Ok(None) => return Err(AppError::InternalError("Internal server error".to_string())),
+            Err(e) => return Err(AppError::Database(e.into()))
+        };
+
+        if user.id != account.user {return Err(AppError::Auth);}
+
+        Ok(())
+    }
+
+    pub async fn update(
+        collection: &Collection<Transaction>,
+        id: ObjectId,
+        data: Option<String>,
+        date: Option<String>
+    ) -> Result<Transaction, AppError> {
+        let filter = doc!{"_id": id};
+        let mut set = Document::new();
+
+        if let Some(d) = data {set.insert("data", d);}
+        if let Some(d) = date {set.insert("date", d);}
+
+        if !set.is_empty() {
+            let result = collection
+                .find_one_and_update(filter, doc!{"$set": set})
+                .return_document(ReturnDocument::After)
+                .await?;
+
+            match result {
+                Some(a) => Ok(a),
+                None => Err(AppError::InvalidInput("No account with this ID".to_string()))
+            }
+        } else {
+            Err(AppError::InvalidInput("Nothing to update".to_string()))
+        }
+    }
+
+
     pub fn response(self) -> ResponseTransaction {
         ResponseTransaction {
             id: self.id.to_hex(),

+ 2 - 0
src/routes/transaction.rs

@@ -3,9 +3,11 @@ use actix_web::web;
 use crate::controllers::transaction::{
     create_route,
     get_many_route,
+    update_route
 };
 
 pub fn config(cfg: &mut web::ServiceConfig) {
     cfg.service(create_route);
     cfg.service(get_many_route);
+    cfg.service(update_route);
 }