From 90a17e64d3daed21029cddf16117197046edaa9a Mon Sep 17 00:00:00 2001 From: Manuel Gugger Date: Wed, 25 May 2022 19:34:29 +0200 Subject: [PATCH] create actix_admin_builder function --- actix_admin/src/lib.rs | 130 +++++++++++++++++++++++++++++------------ database.db-wal | Bin 20632 -> 28872 bytes src/main.rs | 45 +++++--------- 3 files changed, 108 insertions(+), 67 deletions(-) diff --git a/actix_admin/src/lib.rs b/actix_admin/src/lib.rs index 5af561b..02f774d 100644 --- a/actix_admin/src/lib.rs +++ b/actix_admin/src/lib.rs @@ -1,11 +1,11 @@ +use actix_web::http::header; use actix_web::{error, web, Error, HttpRequest, HttpResponse}; +use async_trait::async_trait; use lazy_static::lazy_static; -use sea_orm::{ DatabaseConnection}; +use sea_orm::DatabaseConnection; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use actix_web::http::header; use tera::{Context, Tera}; -use async_trait::async_trait; pub use actix_admin_macros::DeriveActixAdminModel; @@ -48,19 +48,27 @@ pub trait AppDataTrait { // ActixAdminModel #[async_trait] pub trait ActixAdminModelTrait { - async fn list_model(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec; + async fn list_model( + db: &DatabaseConnection, + page: usize, + posts_per_page: usize, + ) -> Vec; fn get_fields() -> Vec<(String, ActixAdminField)>; } #[derive(Clone, Debug, Serialize)] pub struct ActixAdminModel { - pub values: HashMap + pub values: HashMap, } // ActixAdminViewModel #[async_trait(?Send)] pub trait ActixAdminViewModelTrait { - async fn list(db: &DatabaseConnection, page: usize, entities_per_page: usize) -> Vec; + async fn list( + db: &DatabaseConnection, + page: usize, + entities_per_page: usize, + ) -> Vec; async fn create_entity(db: &DatabaseConnection, model: ActixAdminModel) -> ActixAdminModel; fn get_entity_name() -> String; } @@ -71,34 +79,64 @@ pub struct ActixAdminViewModel { pub fields: Vec<(String, ActixAdminField)>, } -// ActixAdminController #[derive(Clone, Debug)] pub struct ActixAdmin { - pub entity_names: Vec, - pub view_models: HashMap + pub entity_names: Vec, + pub view_models: HashMap, } -impl ActixAdmin { - pub fn new() -> Self { - let actix_admin = ActixAdmin { - entity_names: Vec::new(), - view_models: HashMap::new() - }; - actix_admin +pub struct ActixAdminBuilder { + pub scopes: Vec, + pub actix_admin: ActixAdmin, +} + +pub trait ActixAdminBuilderTrait { + fn new() -> Self; + fn add_entity(&mut self, view_model: &ActixAdminViewModel); + fn get_scope(self) -> actix_web::Scope; + fn get_actix_admin(&self) -> ActixAdmin; +} + +impl ActixAdminBuilderTrait for ActixAdminBuilder { + fn new() -> Self { + ActixAdminBuilder { + actix_admin: ActixAdmin { + entity_names: Vec::new(), + view_models: HashMap::new(), + }, + scopes: Vec::new(), + } } - pub fn add_entity(mut self, view_model: &ActixAdminViewModel) -> Self { - self.entity_names.push(E::get_entity_name()); - let view_model_cloned = view_model.clone(); - let key = view_model.entity_name.to_string(); - self.view_models.insert(key, view_model_cloned); - self + fn add_entity( + &mut self, + view_model: &ActixAdminViewModel, + ) { + self.scopes.push( + web::scope(&format!("/{}", E::get_entity_name())) + .route("/list", web::get().to(self::list::)) + .route("/create", web::get().to(self::create_get::)) + .route("/create", web::post().to(self::create_post::)), + ); + + self.actix_admin.entity_names.push(E::get_entity_name()); + //let view_model_cloned = view_model.clone(); + let key = E::get_entity_name(); + self.actix_admin.view_models.insert(key, view_model.clone()); } - pub fn create_scope(&self) -> actix_web::Scope { - let scope = web::scope("/admin").route("/", web::get().to(index::)); + fn get_scope(self) -> actix_web::Scope { + let mut scope = web::scope("/admin").route("/", web::get().to(index::)); + for entity_scope in self.scopes { + scope = scope.service(entity_scope); + } + scope } + + fn get_actix_admin(&self) -> ActixAdmin { + self.actix_admin.clone() + } } impl From for ActixAdminModel { @@ -107,13 +145,13 @@ impl From for ActixAdminModel { let key_values: Vec<&str> = string.split('&').collect(); for key_value in key_values { let mut iter = key_value.splitn(2, '='); - hashmap.insert(iter.next().unwrap().to_string(), iter.next().unwrap().to_string()); + hashmap.insert( + iter.next().unwrap().to_string(), + iter.next().unwrap().to_string(), + ); } - ActixAdminModel { - // TODO: create dynamically - values: hashmap - } + ActixAdminModel { values: hashmap } } } @@ -123,9 +161,9 @@ impl ActixAdminModel { let value = self.values.get(key).unwrap().to_string().parse::(); match value { Ok(val) => Some(val), - Err(_) => None //panic!("key {} could not be parsed", key) + Err(_) => None, //panic!("key {} could not be parsed", key) } - } + } } pub async fn index(data: web::Data) -> Result { @@ -139,7 +177,10 @@ pub async fn index(data: web::Data) -> Result(req: HttpRequest, data: web::Data) -> Result { +pub async fn list( + req: HttpRequest, + data: web::Data, +) -> Result { let entity_name = E::get_entity_name(); let actix_admin = data.get_actix_admin(); let view_model: &ActixAdminViewModel = actix_admin.view_models.get(&entity_name).unwrap(); @@ -148,7 +189,9 @@ pub async fn list(req: HttpRequest let params = web::Query::::from_query(req.query_string()).unwrap(); let page = params.page.unwrap_or(1); - let entities_per_page = params.entities_per_page.unwrap_or(DEFAULT_ENTITIES_PER_PAGE); + let entities_per_page = params + .entities_per_page + .unwrap_or(DEFAULT_ENTITIES_PER_PAGE); let db = data.get_db(); let entities: Vec = E::list(db, page, entities_per_page).await; @@ -167,7 +210,12 @@ pub async fn list(req: HttpRequest Ok(HttpResponse::Ok().content_type("text/html").body(body)) } -pub async fn create_get(_req: HttpRequest, data: web::Data, _body: web::Payload, _text: String) -> Result { +pub async fn create_get( + _req: HttpRequest, + data: web::Data, + _body: web::Payload, + _text: String, +) -> Result { let _db = &data.get_db(); let entity_name = E::get_entity_name(); let entity_names = &data.get_actix_admin().entity_names; @@ -187,16 +235,22 @@ pub async fn create_get(_req: Http Ok(HttpResponse::Ok().content_type("text/html").body(body)) } -pub async fn create_post(_req: HttpRequest, data: web::Data, text: String) -> Result { +pub async fn create_post( + _req: HttpRequest, + data: web::Data, + text: String, +) -> Result { let db = &data.get_db(); let entity_name = E::get_entity_name(); let actix_admin = data.get_actix_admin(); - let view_model = actix_admin.view_models.get(&entity_name).unwrap(); let mut admin_model = ActixAdminModel::from(text); admin_model = E::create_entity(db, admin_model).await; Ok(HttpResponse::Found() - .append_header((header::LOCATION, format!("/admin/{}/list", view_model.entity_name))) + .append_header(( + header::LOCATION, + format!("/admin/{}/list", view_model.entity_name), + )) .finish()) -} \ No newline at end of file +} diff --git a/database.db-wal b/database.db-wal index 6c56214d98e6659fd79ab59cbcf33f14ca7fefaa..d3527e88240e1df29cecdf4a6c56c2f41f6de9b5 100644 GIT binary patch delta 121 zcmbQSknzMr#tkz9lo%Kon1Gn!tNEMt_YI`JtzDjdMEgVkT3(5s9zA>-x>J719iXU=VWJO L7Ue9+FD?N96geo6 delta 9 QcmX@{ka5OB#tkz902pZmeE) -> HttpResponse { HttpResponse::Ok().body(rendered) } -// TODO: Generate this with a Macro accepting Tuples of (Entity, viewmodel) -fn setup_actix_admin( - actix_admin: &ActixAdmin, -) -> actix_web::Scope { - actix_admin - .create_scope::() - .service( - web::scope("/post") - .route("/list", web::get().to(actix_admin::list::)) - .route("/create", web::get().to(actix_admin::create_get::)) - .route("/create", web::post().to(actix_admin::create_post::)) - ) - .service( - web::scope("/comment") - .route("/list", web::get().to(actix_admin::list::)) - .route("/create", web::get().to(actix_admin::create_get::)) - .route("/create", web::post().to(actix_admin::create_post::)) - ) +fn create_actix_admin_builder() -> ActixAdminBuilder { + let post_view_model = ActixAdminViewModel::from(Post); + let comment_view_model = ActixAdminViewModel::from(Comment); + + let mut admin_builder = ActixAdminBuilder::new(); + admin_builder.add_entity::(&post_view_model); + admin_builder.add_entity::(&comment_view_model); + + admin_builder } #[actix_rt::main] @@ -109,17 +100,13 @@ async fn main() { let conn = sea_orm::Database::connect(opt).await.unwrap(); let _ = entity::create_post_table(&conn).await; - let post_view_model = ActixAdminViewModel::from(Post); - let comment_view_model = ActixAdminViewModel::from(Comment); - let actix_admin = ActixAdmin::new() - .add_entity::(&post_view_model) - .add_entity::(&comment_view_model) - ; + let actix_admin = create_actix_admin_builder().get_actix_admin(); + let app_state = AppState { oauth: client, tmpl: tera, db: conn, - actix_admin: actix_admin.clone(), + actix_admin: actix_admin, }; HttpServer::new(move || { @@ -128,9 +115,9 @@ async fn main() { .wrap(CookieSession::signed(&[0; 32]).secure(false)) .route("/", web::get().to(index)) .service(azure_auth.clone().create_scope::()) - .service(setup_actix_admin( - &actix_admin - )) + .service( + create_actix_admin_builder().get_scope::() + ) .wrap(middleware::Logger::default()) }) .bind("127.0.0.1:5000")