store actix_admin in appstate

This commit is contained in:
Manuel Gugger 2022-04-26 15:28:52 +02:00
parent 9923ae6a69
commit b5f55487fa
5 changed files with 44 additions and 20 deletions

View File

@ -40,8 +40,9 @@ pub fn derive_crud_fns(_input: proc_macro::TokenStream) -> proc_macro::TokenStre
async fn list<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error> {
let db = &data.get_db();
let entities = Entity::list_db(db, 1, 5);
let entity_names = &data.get_actix_admin().entity_names;
let model = ActixAdminViewModel::from(Entity);
actix_admin::list_model(req, model)
actix_admin::list_model(req, &data, model, entity_names)
}
}
};

View File

@ -1,5 +1,5 @@
use actix_web::error::ErrorBadRequest;
use actix_web::{dev, App, FromRequest};
use actix_web::{dev, App, FromRequest, Route};
use actix_web::{error, guard, web, Error, HttpRequest, HttpResponse};
use futures::future::{err, ok, Ready};
use lazy_static::lazy_static;
@ -18,7 +18,7 @@ pub use actix_admin_macros::DeriveActixAdminModel;
const DEFAULT_POSTS_PER_PAGE: usize = 5;
// templates
// globals
lazy_static! {
static ref TERA: Tera =
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
@ -40,6 +40,7 @@ pub enum Field {
// AppDataTrait
pub trait AppDataTrait {
fn get_db(&self) -> &DatabaseConnection;
fn get_actix_admin(&self) -> &ActixAdmin;
}
// ActixAdminModel
@ -61,22 +62,29 @@ pub trait ActixAdminViewModelTrait {
#[derive(Clone, Debug, Serialize)]
pub struct ActixAdminViewModel {
pub entity_name: String
pub entity_name: String,
}
// ActixAdminController
#[derive(Clone, Debug)]
pub struct ActixAdmin {
pub entity_names: Vec<String>
}
impl ActixAdmin {
pub fn new() -> Self {
let actix_admin = ActixAdmin {
entity_names: Vec::new()
};
actix_admin
}
pub fn create_scope<T: AppDataTrait + 'static>(self, _app_state: &T) -> actix_web::Scope {
pub fn add_entity<T: AppDataTrait + 'static>(mut self, view_model: &ActixAdminViewModel) -> Self {
self.entity_names.push(view_model.entity_name.to_string());
self
}
pub fn create_scope<T: AppDataTrait + 'static>(&self) -> actix_web::Scope {
let scope = web::scope("/admin").route("/", web::get().to(index::<T>));
scope
@ -85,9 +93,9 @@ impl ActixAdmin {
async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse, Error> {
let view_models: Vec<&str> = Vec::new();
let entity_names = &data.get_actix_admin().entity_names;
let mut ctx = Context::new();
ctx.insert("view_models", &view_models);
ctx.insert("entity_names", &entity_names);
let body = TERA
.render("index.html", &ctx)
@ -95,7 +103,7 @@ async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse, Erro
Ok(HttpResponse::Ok().content_type("text/html").body(body))
}
pub fn list_model(req: HttpRequest, view_model: ActixAdminViewModel) -> Result<HttpResponse, Error> {
pub fn list_model<T: AppDataTrait>(req: HttpRequest, data: &web::Data<T>, view_model: ActixAdminViewModel, entity_names: &Vec<String>) -> Result<HttpResponse, Error> {
let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
let page = params.page.unwrap_or(1);
@ -104,10 +112,9 @@ pub fn list_model(req: HttpRequest, view_model: ActixAdminViewModel) -> Result<H
let columns: Vec<String> = Vec::new();
let entities: Vec<&str> = Vec::new(); // view_model.get_entities()
let view_models: Vec<&str> = Vec::new();
let mut ctx = Context::new();
ctx.insert("view_models", &view_models);
ctx.insert("entity_names", &entity_names);
ctx.insert("posts", &entities);
ctx.insert("page", &page);
ctx.insert("posts_per_page", &posts_per_page);

View File

@ -4,8 +4,8 @@
<li>Actix Admin</li>
</ul>
<ul>
{% for view_model in view_models -%}
<li><a href="/admin/{{ view_model.entity_name}}/list" class="secondary">{{ view_model.entity_name }}</a></li>
{% for entity_name in entity_names -%}
<li><a href="/admin/{{ entity_name }}/list" class="secondary">{{ entity_name }}</a></li>
{%- endfor %}
</ul>
</nav>

View File

@ -66,7 +66,7 @@ impl AzureAuth {
)
}
pub fn create_scope<T: AppDataTrait + 'static>(self, _app_state: &T) -> actix_web::Scope {
pub fn create_scope<T: AppDataTrait + 'static>(self) -> actix_web::Scope {
let scope = web::scope("/auth")
.route("/login", web::get().to(login::<T>))
.route("/logout", web::get().to(logout))

View File

@ -1,15 +1,14 @@
extern crate serde_derive;
use actix_session::{Session, CookieSession};
use actix_web::{web, App, HttpResponse, HttpServer, HttpRequest, Error};
use actix_web::{web, App, HttpResponse, HttpServer};
use tera::{ Tera, Context};
use oauth2::basic::BasicClient;
use oauth2::{ RedirectUrl };
use std::time::{Duration};
use std::env;
use sea_orm::{{ DatabaseConnection, ConnectOptions }};
use std::any::Any;
use actix_admin::{ AppDataTrait as ActixAdminAppDataTrait, ActixAdminViewModelTrait };
use actix_admin::{ AppDataTrait as ActixAdminAppDataTrait, ActixAdminViewModel, ActixAdmin, ActixAdminViewModelTrait };
use azure_auth::{ AzureAuth, UserInfo, AppDataTrait as AzureAuthAppDataTrait };
mod entity;
@ -20,12 +19,16 @@ pub struct AppState {
pub oauth: BasicClient,
pub tmpl: Tera,
pub db: DatabaseConnection,
pub actix_admin: ActixAdmin
}
impl ActixAdminAppDataTrait for AppState {
fn get_db(&self) -> &DatabaseConnection {
&self.db
}
fn get_actix_admin(&self) -> &ActixAdmin {
&self.actix_admin
}
}
impl AzureAuthAppDataTrait for AppState {
@ -76,10 +79,17 @@ 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::<AppState>(&post_view_model)
.add_entity::<AppState>(&comment_view_model);
let app_state = AppState {
oauth: client,
tmpl: tera,
db: conn,
actix_admin: actix_admin.clone()
};
HttpServer::new(move || {
@ -87,12 +97,18 @@ async fn main() {
.app_data(web::Data::new(app_state.clone()))
.wrap(CookieSession::signed(&[0; 32]).secure(false))
.route("/", web::get().to(index))
.service(azure_auth.clone().create_scope(&app_state))
.service(azure_auth.clone().create_scope::<AppState>())
.service(
actix_admin::ActixAdmin::new()
.create_scope(&app_state)
// TODO: Generate this with a Macro accepting Tuples of (Entity, viewmodel)
actix_admin
.create_scope::<AppState>()
.service(
web::scope(&format!("/{}", "posts")).route("/list", web::get().to(Post::list::<AppState>)),
web::scope(&format!("/{}", post_view_model.entity_name))
.route("/list", web::get().to(Post::list::<AppState>)),
)
.service(
web::scope(&format!("/{}", comment_view_model.entity_name))
.route("/list", web::get().to(Comment::list::<AppState>)),
)
)
})