move function out of lib

This commit is contained in:
Manuel Gugger 2022-04-25 21:00:42 +02:00
parent 657ad8ffc9
commit 7648c4bced
4 changed files with 90 additions and 66 deletions

View File

@ -1,16 +1,16 @@
use actix_web::{error, guard, web, Error, HttpRequest, HttpResponse};
use actix_web::{ dev, App, FromRequest};
use actix_web::error::ErrorBadRequest; use actix_web::error::ErrorBadRequest;
use serde::{Deserialize, Serialize}; use actix_web::{dev, App, FromRequest};
use std::collections::HashMap; use actix_web::{error, guard, web, Error, HttpRequest, HttpResponse};
use tera::{Context, Tera}; use futures::future::{err, ok, Ready};
use futures::future::{ok, err, Ready};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use sea_orm::EntityTrait; use sea_orm::EntityTrait;
use sea_orm::ModelTrait; use sea_orm::ModelTrait;
use std::pin::Pin; use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::collections::HashMap;
use std::pin::Pin;
use tera::{Context, Tera};
use async_trait::async_trait; use async_trait::async_trait;
@ -20,7 +20,8 @@ const DEFAULT_POSTS_PER_PAGE: usize = 5;
// templates // templates
lazy_static! { lazy_static! {
static ref TERA: Tera = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); static ref TERA: Tera =
Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap();
} }
// Paging // Paging
@ -33,19 +34,18 @@ pub struct Params {
// Fields // Fields
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub enum Field { pub enum Field {
Text Text,
} }
// AppDataTrait // AppDataTrait
pub trait AppDataTrait { pub trait AppDataTrait {
fn get_db(&self) -> &DatabaseConnection; fn get_db(&self) -> &DatabaseConnection;
fn get_view_model_map(&self) -> &HashMap<&'static str, ActixAdminViewModel>;
} }
// ActixAdminModel // ActixAdminModel
#[async_trait] #[async_trait]
pub trait ActixAdminModelTrait : Clone { pub trait ActixAdminModelTrait: Clone {
async fn list(&self, db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str>; async fn list(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str>;
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
@ -54,68 +54,47 @@ pub struct ActixAdminModel {
} }
// ActixAdminViewModel // ActixAdminViewModel
pub trait ActixAdminViewModelTrait : Clone { pub trait ActixAdminViewModelTrait: Clone {
fn get_model_name(&self) -> &str; fn get_model_name(&self) -> &str;
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct ActixAdminViewModel { pub struct ActixAdminViewModel {
pub entity_name: &'static str, pub entity_name: String
pub admin_model: ActixAdminModel
} }
// ActixAdminController // ActixAdminController
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ActixAdmin { pub struct ActixAdmin {
view_models: HashMap<&'static str, ActixAdminViewModel>,
} }
impl ActixAdmin { impl ActixAdmin {
pub fn new() -> Self { pub fn new() -> Self {
let actix_admin = ActixAdmin { let actix_admin = ActixAdmin {
view_models: HashMap::new(),
}; };
actix_admin actix_admin
} }
pub fn create_scope<T: AppDataTrait + 'static>(self, _app_state: &T) -> actix_web::Scope { pub fn create_scope<T: AppDataTrait + 'static>(self, _app_state: &T) -> actix_web::Scope {
let mut scope = web::scope("/admin").route("/", web::get().to(index::<T>)); let scope = web::scope("/admin").route("/", web::get().to(index::<T>));
for view_model in self.view_models {
scope = scope.service(
web::scope(&format!("/{}", view_model.0)).route("/list", web::get().to(list::<T>))
);
}
scope scope
} }
pub fn add_entity(mut self, view_model: ActixAdminViewModel) -> Self {
self.view_models.insert(view_model.entity_name, view_model);
self
}
pub fn get_view_model_map(&self) -> HashMap<&'static str, ActixAdminViewModel> {
self.view_models.clone()
}
} }
async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse, Error> { async fn index<T: AppDataTrait>(data: web::Data<T>) -> Result<HttpResponse, Error> {
let view_models = Vec::from_iter(data.get_view_model_map().values());
let view_models: Vec<&str> = Vec::new();
let mut ctx = Context::new(); let mut ctx = Context::new();
ctx.insert("view_models", &view_models); ctx.insert("view_models", &view_models);
let body = TERA let body = TERA
.render("index.html", &ctx) .render("index.html", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?; .map_err(|_| error::ErrorInternalServerError("Template error"))?;
Ok(HttpResponse::Ok().content_type("text/html").body(body)) Ok(HttpResponse::Ok().content_type("text/html").body(body))
} }
async fn list<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error> { pub fn list_model(req: HttpRequest, view_model: ActixAdminViewModel) -> Result<HttpResponse, Error> {
let view_model = data.get_view_model_map().get("posts").unwrap();
let db = &data.get_db();
let params = web::Query::<Params>::from_query(req.query_string()).unwrap(); let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
let page = params.page.unwrap_or(1); let page = params.page.unwrap_or(1);
@ -133,7 +112,7 @@ async fn list<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<H
ctx.insert("columns", &columns); ctx.insert("columns", &columns);
let body = TERA let body = TERA
.render("list.html", &ctx) .render("list.html", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?; .map_err(|_| error::ErrorInternalServerError("Template error"))?;
Ok(HttpResponse::Ok().content_type("text/html").body(body)) Ok(HttpResponse::Ok().content_type("text/html").body(body))
} }

47
src/entity/comment.rs Normal file
View File

@ -0,0 +1,47 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
use actix_admin::{ DeriveActixAdminModel };
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdminModel)]
#[sea_orm(table_name = "comment")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
pub title: String,
#[sea_orm(column_type = "Text")]
pub text: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
impl From<Entity> for ActixAdminModel {
fn from(entity: Entity) -> Self {
ActixAdminModel {
fields: Vec::new()
}
}
}
#[async_trait]
impl ActixAdminModelTrait for Entity {
async fn list(&self, db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str> {
use sea_orm::{ query::* };
let paginator = Entity::find()
.order_by_asc(Column::Id)
.paginate(db, posts_per_page);
let entities = paginator
.fetch_page(page - 1)
.await
.expect("could not retrieve entities");
//entities to ActixAdminModel
vec![
]
}
}

View File

@ -1,7 +1,7 @@
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use actix_admin::{ DeriveActixAdminModel }; use actix_admin::{ DeriveActixAdminModel, ActixAdminViewModel };
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdminModel)] #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdminModel)]
#[sea_orm(table_name = "post")] #[sea_orm(table_name = "post")]
@ -19,18 +19,17 @@ pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {} impl ActiveModelBehavior for ActiveModel {}
impl From<Entity> for ActixAdminViewModel {
impl From<Entity> for ActixAdminModel {
fn from(entity: Entity) -> Self { fn from(entity: Entity) -> Self {
ActixAdminModel { ActixAdminViewModel {
fields: Vec::new() entity_name: entity.table_name().to_string()
} }
} }
} }
#[async_trait] #[async_trait]
impl ActixAdminModelTrait for Entity { impl ActixAdminModelTrait for Entity {
async fn list(&self, db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str> { async fn list(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str> {
use sea_orm::{ query::* }; use sea_orm::{ query::* };
let paginator = Entity::find() let paginator = Entity::find()
.order_by_asc(Column::Id) .order_by_asc(Column::Id)

View File

@ -1,16 +1,15 @@
extern crate serde_derive; extern crate serde_derive;
use actix_session::{Session, CookieSession}; use actix_session::{Session, CookieSession};
use actix_web::{web, App, HttpResponse, HttpServer}; use actix_web::{web, App, HttpResponse, HttpServer, HttpRequest, Error};
use tera::{ Tera, Context}; use tera::{ Tera, Context};
use oauth2::basic::BasicClient; use oauth2::basic::BasicClient;
use oauth2::{ RedirectUrl }; use oauth2::{ RedirectUrl };
use std::time::{Duration}; use std::time::{Duration};
use std::env; use std::env;
use std::collections::HashMap;
use sea_orm::{{ DatabaseConnection, ConnectOptions }}; use sea_orm::{{ DatabaseConnection, ConnectOptions }};
use actix_admin::{ AppDataTrait as ActixAdminAppDataTrait, ActixAdminViewModel, ActixAdminModel}; use actix_admin::{ AppDataTrait as ActixAdminAppDataTrait, ActixAdminViewModel, ActixAdminModelTrait};
use azure_auth::{ AzureAuth, UserInfo, AppDataTrait as AzureAuthAppDataTrait }; use azure_auth::{ AzureAuth, UserInfo, AppDataTrait as AzureAuthAppDataTrait };
mod entity; mod entity;
@ -21,17 +20,12 @@ pub struct AppState {
pub oauth: BasicClient, pub oauth: BasicClient,
pub tmpl: Tera, pub tmpl: Tera,
pub db: DatabaseConnection, pub db: DatabaseConnection,
pub view_model_map: HashMap<&'static str, ActixAdminViewModel>
} }
impl ActixAdminAppDataTrait for AppState { impl ActixAdminAppDataTrait for AppState {
fn get_db(&self) -> &DatabaseConnection { fn get_db(&self) -> &DatabaseConnection {
&self.db &self.db
} }
fn get_view_model_map(&self) -> &HashMap<&'static str, ActixAdminViewModel> {
&self.view_model_map
}
} }
impl AzureAuthAppDataTrait for AppState { impl AzureAuthAppDataTrait for AppState {
@ -82,19 +76,10 @@ async fn main() {
let conn = sea_orm::Database::connect(opt).await.unwrap(); let conn = sea_orm::Database::connect(opt).await.unwrap();
let _ = entity::create_post_table(&conn).await; let _ = entity::create_post_table(&conn).await;
let viewmodel_entity = ActixAdminViewModel {
entity_name: "posts",
admin_model: ActixAdminModel::from(Post)
};
let actix_admin = actix_admin::ActixAdmin::new()
.add_entity(viewmodel_entity.clone());
let app_state = AppState { let app_state = AppState {
oauth: client, oauth: client,
tmpl: tera, tmpl: tera,
db: conn, db: conn,
view_model_map: actix_admin.get_view_model_map()
}; };
HttpServer::new(move || { HttpServer::new(move || {
@ -102,8 +87,14 @@ async fn main() {
.app_data(web::Data::new(app_state.clone())) .app_data(web::Data::new(app_state.clone()))
.wrap(CookieSession::signed(&[0; 32]).secure(false)) .wrap(CookieSession::signed(&[0; 32]).secure(false))
.route("/", web::get().to(index)) .route("/", web::get().to(index))
.service(actix_admin.clone().create_scope(&app_state))
.service(azure_auth.clone().create_scope(&app_state)) .service(azure_auth.clone().create_scope(&app_state))
.service(
actix_admin::ActixAdmin::new()
.create_scope(&app_state)
.service(
web::scope(&format!("/{}", "posts")).route("/list", web::get().to(list)),
)
)
}) })
.bind("127.0.0.1:5000") .bind("127.0.0.1:5000")
.expect("Can not bind to port 5000") .expect("Can not bind to port 5000")
@ -111,3 +102,11 @@ async fn main() {
.await .await
.unwrap(); .unwrap();
} }
// Actix admin Routes to be auto generated
async fn list(req: HttpRequest, data: web::Data<AppState>)-> Result<HttpResponse, Error> {
let db = &data.get_db();
let entities = Post::list(db, 1, 5);
let model = ActixAdminViewModel::from(Post);
actix_admin::list_model(req, model)
}