create actix_admin_builder function
This commit is contained in:
parent
7c8cf72668
commit
90a17e64d3
@ -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<ActixAdminModel>;
|
||||
async fn list_model(
|
||||
db: &DatabaseConnection,
|
||||
page: usize,
|
||||
posts_per_page: usize,
|
||||
) -> Vec<ActixAdminModel>;
|
||||
fn get_fields() -> Vec<(String, ActixAdminField)>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct ActixAdminModel {
|
||||
pub values: HashMap<String, String>
|
||||
pub values: HashMap<String, String>,
|
||||
}
|
||||
|
||||
// ActixAdminViewModel
|
||||
#[async_trait(?Send)]
|
||||
pub trait ActixAdminViewModelTrait {
|
||||
async fn list(db: &DatabaseConnection, page: usize, entities_per_page: usize) -> Vec<ActixAdminModel>;
|
||||
async fn list(
|
||||
db: &DatabaseConnection,
|
||||
page: usize,
|
||||
entities_per_page: usize,
|
||||
) -> Vec<ActixAdminModel>;
|
||||
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<String>,
|
||||
pub view_models: HashMap<String, ActixAdminViewModel>
|
||||
pub view_models: HashMap<String, ActixAdminViewModel>,
|
||||
}
|
||||
|
||||
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<actix_web::Scope>,
|
||||
pub actix_admin: ActixAdmin,
|
||||
}
|
||||
|
||||
pub trait ActixAdminBuilderTrait {
|
||||
fn new() -> Self;
|
||||
fn add_entity<T: AppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(&mut self, view_model: &ActixAdminViewModel);
|
||||
fn get_scope<T: AppDataTrait + 'static>(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<E: ActixAdminViewModelTrait>(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<T: AppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
|
||||
&mut self,
|
||||
view_model: &ActixAdminViewModel,
|
||||
) {
|
||||
self.scopes.push(
|
||||
web::scope(&format!("/{}", E::get_entity_name()))
|
||||
.route("/list", web::get().to(self::list::<T, E>))
|
||||
.route("/create", web::get().to(self::create_get::<T, E>))
|
||||
.route("/create", web::post().to(self::create_post::<T, E>)),
|
||||
);
|
||||
|
||||
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<T: AppDataTrait + 'static >(&self) -> actix_web::Scope {
|
||||
let scope = web::scope("/admin").route("/", web::get().to(index::<T>));
|
||||
fn get_scope<T: AppDataTrait + 'static>(self) -> actix_web::Scope {
|
||||
let mut scope = web::scope("/admin").route("/", web::get().to(index::<T>));
|
||||
for entity_scope in self.scopes {
|
||||
scope = scope.service(entity_scope);
|
||||
}
|
||||
|
||||
scope
|
||||
}
|
||||
|
||||
fn get_actix_admin(&self) -> ActixAdmin {
|
||||
self.actix_admin.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ActixAdminModel {
|
||||
@ -107,13 +145,13 @@ impl From<String> 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,7 +161,7 @@ impl ActixAdminModel {
|
||||
let value = self.values.get(key).unwrap().to_string().parse::<T>();
|
||||
match value {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => None //panic!("key {} could not be parsed", key)
|
||||
Err(_) => None, //panic!("key {} could not be parsed", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,7 +177,10 @@ pub async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse,
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||
}
|
||||
|
||||
pub async fn list<T: AppDataTrait, E: ActixAdminViewModelTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error> {
|
||||
pub async fn list<T: AppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
req: HttpRequest,
|
||||
data: web::Data<T>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
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<T: AppDataTrait, E: ActixAdminViewModelTrait>(req: HttpRequest
|
||||
let params = web::Query::<Params>::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<ActixAdminModel> = E::list(db, page, entities_per_page).await;
|
||||
@ -167,7 +210,12 @@ pub async fn list<T: AppDataTrait, E: ActixAdminViewModelTrait>(req: HttpRequest
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||
}
|
||||
|
||||
pub async fn create_get<T: AppDataTrait, E: ActixAdminViewModelTrait>(_req: HttpRequest, data: web::Data<T>, _body: web::Payload, _text: String) -> Result<HttpResponse, Error> {
|
||||
pub async fn create_get<T: AppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
_req: HttpRequest,
|
||||
data: web::Data<T>,
|
||||
_body: web::Payload,
|
||||
_text: String,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
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<T: AppDataTrait, E: ActixAdminViewModelTrait>(_req: Http
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||
}
|
||||
|
||||
pub async fn create_post<T: AppDataTrait, E: ActixAdminViewModelTrait>(_req: HttpRequest, data: web::Data<T>, text: String) -> Result<HttpResponse, Error> {
|
||||
pub async fn create_post<T: AppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
_req: HttpRequest,
|
||||
data: web::Data<T>,
|
||||
text: String,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
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())
|
||||
}
|
BIN
database.db-wal
BIN
database.db-wal
Binary file not shown.
45
src/main.rs
45
src/main.rs
@ -1,7 +1,7 @@
|
||||
extern crate serde_derive;
|
||||
|
||||
use actix_admin::{
|
||||
ActixAdmin, ActixAdminViewModel,
|
||||
ActixAdmin, ActixAdminBuilder, ActixAdminBuilderTrait, ActixAdminViewModel,
|
||||
AppDataTrait as ActixAdminAppDataTrait,
|
||||
};
|
||||
use actix_session::{CookieSession, Session};
|
||||
@ -55,24 +55,15 @@ async fn index(session: Session, data: web::Data<AppState>) -> 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::<AppState>()
|
||||
.service(
|
||||
web::scope("/post")
|
||||
.route("/list", web::get().to(actix_admin::list::<AppState, Post>))
|
||||
.route("/create", web::get().to(actix_admin::create_get::<AppState, Post>))
|
||||
.route("/create", web::post().to(actix_admin::create_post::<AppState, Post>))
|
||||
)
|
||||
.service(
|
||||
web::scope("/comment")
|
||||
.route("/list", web::get().to(actix_admin::list::<AppState, Comment>))
|
||||
.route("/create", web::get().to(actix_admin::create_get::<AppState, Comment>))
|
||||
.route("/create", web::post().to(actix_admin::create_post::<AppState, Comment>))
|
||||
)
|
||||
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::<AppState, Post>(&post_view_model);
|
||||
admin_builder.add_entity::<AppState, Comment>(&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>(&post_view_model)
|
||||
.add_entity::<Comment>(&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::<AppState>())
|
||||
.service(setup_actix_admin(
|
||||
&actix_admin
|
||||
))
|
||||
.service(
|
||||
create_actix_admin_builder().get_scope::<AppState>()
|
||||
)
|
||||
.wrap(middleware::Logger::default())
|
||||
})
|
||||
.bind("127.0.0.1:5000")
|
||||
|
Loading…
Reference in New Issue
Block a user