diff --git a/actix_admin/Cargo.toml b/actix_admin/Cargo.toml index 02fff0e..cc31fc7 100644 --- a/actix_admin/Cargo.toml +++ b/actix_admin/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] actix-web = "4.0.1" +actix-multipart = "0.4.0" +futures-util = "0.3.21" tera = "1.16.0" actix_admin_macros = { path = "actix_admin_macros" } async-trait = "0.1.53" diff --git a/actix_admin/src/lib.rs b/actix_admin/src/lib.rs index 52c9fe2..0c2b5b8 100644 --- a/actix_admin/src/lib.rs +++ b/actix_admin/src/lib.rs @@ -67,7 +67,6 @@ pub fn get_html_input_type(value: &tera::Value, _: &HashMap &DatabaseConnection; diff --git a/actix_admin/src/model.rs b/actix_admin/src/model.rs index bb554f9..457556b 100644 --- a/actix_admin/src/model.rs +++ b/actix_admin/src/model.rs @@ -3,6 +3,8 @@ use async_trait::async_trait; use sea_orm::DatabaseConnection; use serde::Serialize; use std::collections::HashMap; +use actix_multipart:: {Multipart, MultipartError} ; +use futures_util::stream::StreamExt as _; #[async_trait] pub trait ActixAdminModelTrait { @@ -27,29 +29,41 @@ pub struct ActixAdminModel { pub errors: HashMap, } -impl From for ActixAdminModel { - fn from(string: String) -> Self { - let mut hashmap = HashMap::new(); - let key_values: Vec<&str> = string.split('&').collect(); - for key_value in key_values { - if !key_value.is_empty() { - let mut iter = key_value.splitn(2, '='); - hashmap.insert( - iter.next().unwrap().to_string(), - iter.next().unwrap().to_string(), - ); - } - } - +impl ActixAdminModel { + pub fn create_empty() -> ActixAdminModel { ActixAdminModel { primary_key: None, - values: hashmap, + values: HashMap::new(), errors: HashMap::new(), } } -} -impl ActixAdminModel { + pub async fn create_from_payload(mut payload: Multipart) -> Result { + let mut hashmap = HashMap::::new(); + + while let Some(item) = payload.next().await { + let mut field = item?; + + // TODO: how to handle binary chunks? + while let Some(chunk) = field.next().await { + //println!("-- CHUNK: \n{:?}", String::from_utf8(chunk.map_or(Vec::new(), |c| c.to_vec()))); + let res_string = String::from_utf8(chunk.map_or(Vec::new(), |c| c.to_vec())); + if res_string.is_ok() { + hashmap.insert( + field.name().to_string(), + res_string.unwrap() + ); + } + } + } + + Ok(ActixAdminModel { + primary_key: None, + values: hashmap, + errors: HashMap::new(), + }) + } + pub fn get_value(&self, key: &str, is_option_or_string: bool) -> Result, String> { let value = self.values.get(key); @@ -60,6 +74,7 @@ impl ActixAdminModel { } let parsed_val = val.parse::(); + println!("{:?}", val); match parsed_val { Ok(val) => Ok(Some(val)), diff --git a/actix_admin/src/routes/create_or_edit_get.rs b/actix_admin/src/routes/create_or_edit_get.rs index bf2abfc..cfd0c9b 100644 --- a/actix_admin/src/routes/create_or_edit_get.rs +++ b/actix_admin/src/routes/create_or_edit_get.rs @@ -9,10 +9,10 @@ pub async fn create_get( _req: HttpRequest, data: web::Data, _body: web::Payload, - text: String, + _text: String, ) -> Result { let db = &data.get_db(); - let model = ActixAdminModel::from(text); + let model = ActixAdminModel::create_empty(); create_or_edit_get::(&data, db, model).await } diff --git a/actix_admin/src/routes/create_or_edit_post.rs b/actix_admin/src/routes/create_or_edit_post.rs index 741aa45..27f4983 100644 --- a/actix_admin/src/routes/create_or_edit_post.rs +++ b/actix_admin/src/routes/create_or_edit_post.rs @@ -2,16 +2,17 @@ use actix_web::http::header; use actix_web::{web, error, Error, HttpRequest, HttpResponse}; use tera::{Context}; use crate::TERA; +use actix_multipart::Multipart; use crate::prelude::*; pub async fn create_post( _req: HttpRequest, data: web::Data, - text: String, + payload: Multipart, ) -> Result { let db = &data.get_db(); - let mut model = ActixAdminModel::from(text); + let mut model = ActixAdminModel::create_from_payload(payload).await.unwrap(); model = E::create_entity(db, model).await; create_or_edit_post::(&data, db, model).await @@ -20,11 +21,11 @@ pub async fn create_post pub async fn edit_post( _req: HttpRequest, data: web::Data, - text: String, + payload: Multipart, id: web::Path ) -> Result { let db = &data.get_db(); - let mut model = ActixAdminModel::from(text); + let mut model = ActixAdminModel::create_from_payload(payload).await.unwrap(); model = E::edit_entity(db, id.into_inner(), model).await; create_or_edit_post::(&data, db, model).await @@ -35,6 +36,7 @@ async fn create_or_edit_post +
{% for model_field in view_model.fields -%}