diff --git a/actix_admin/actix_admin_macros/src/lib.rs b/actix_admin/actix_admin_macros/src/lib.rs index 7b5da34..797e4d8 100644 --- a/actix_admin/actix_admin_macros/src/lib.rs +++ b/actix_admin/actix_admin_macros/src/lib.rs @@ -1,18 +1,16 @@ use proc_macro; use quote::quote; -use proc_macro2::{Span, Ident}; -use syn::{ DeriveInput }; mod struct_fields; -use struct_fields::get_field_for_tokenstream; +use struct_fields::get_fields_for_tokenstream; #[proc_macro_derive(DeriveActixAdminModel)] pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let fields = get_field_for_tokenstream(input); + let fields = get_fields_for_tokenstream(input); let names_const_fields_str = fields.iter().map(|(_vis, ident)| { let ident_name = ident.to_string(); - quote! { + quote! { #ident_name } }); @@ -22,6 +20,10 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea use async_trait::async_trait; use actix_web::{web, HttpResponse, HttpRequest, Error}; use actix_admin::{ ActixAdminField, ActixAdminModelTrait, ActixAdminViewModelTrait, ActixAdminViewModel, ActixAdminModel, AppDataTrait }; + use sea_orm::ActiveValue::Set; + use sea_orm::{ConnectOptions, DatabaseConnection}; + use sea_orm::{entity::*, query::*}; + use sea_orm::EntityTrait; impl From for ActixAdminViewModel { fn from(entity: Entity) -> Self { @@ -31,18 +33,42 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea } } } - + #[async_trait(?Send)] impl ActixAdminViewModelTrait for Entity { async fn list(req: HttpRequest, data: web::Data) -> Result { - 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); + let entity_names = &data.get_actix_admin().entity_names; + + let db = data.get_db(); + let entities = Entity::list_db(db, 1, 5); + // TODO: Get ViewModel from ActixAdmin to honor individual settings actix_admin::list_model(req, &data, model, entity_names) } + + async fn create_get(req: HttpRequest, data: web::Data) -> Result { + let db = &data.get_db(); + let entity_names = &data.get_actix_admin().entity_names; + // TODO: Get ViewModel from ActixAdmin to honor individual settings + let model = ActixAdminViewModel::from(Entity); + actix_admin::create_get_model(req, &data, model, entity_names) + } + + async fn create_post(req: HttpRequest, data: web::Data, post_form: web::Form) -> Result { + let view_model = ActixAdminViewModel::from(Entity); + + let form = post_form.into_inner(); + + let new_model = ActiveModel { + title: Set("test".to_string()), + text: Set("test".to_string()), + ..Default::default() + }; + let insert_operation = Entity::insert(new_model).exec(data.get_db()).await; + + actix_admin::create_post_model(req, &data, view_model) + } } - #[async_trait] impl ActixAdminModelTrait for Entity { async fn list_db(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str> { @@ -56,21 +82,23 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea .expect("could not retrieve entities"); //entities to ActixAdminModel vec![ - ] } - fn get_fields() -> Vec<(&'static str, ActixAdminField)> { + fn get_fields() -> Vec<(String, ActixAdminField)> { let mut vec = Vec::new(); - let field_names = stringify!( + let field_names = stringify!( #(#names_const_fields_str),* ).split(",") .collect::>() .into_iter() - .for_each( |field_name| + .for_each( |field_name| vec.push(( - field_name, - // TODO: derive correct AxtixAdminField Value + field_name + .replace('"', "") + .replace(' ', "") + .to_string(), + // TODO: match correct ActixAdminField Value ActixAdminField::Text ) ) diff --git a/actix_admin/actix_admin_macros/src/struct_fields.rs b/actix_admin/actix_admin_macros/src/struct_fields.rs index ffc518d..494a9e2 100644 --- a/actix_admin/actix_admin_macros/src/struct_fields.rs +++ b/actix_admin/actix_admin_macros/src/struct_fields.rs @@ -5,7 +5,7 @@ use syn::{ const ATTR_META_SKIP: &'static str = "skip"; -pub fn get_field_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<(syn::Visibility, proc_macro2::Ident)> { +pub fn get_fields_for_tokenstream(input: proc_macro::TokenStream) -> std::vec::Vec<(syn::Visibility, proc_macro2::Ident)> { let ast: DeriveInput = syn::parse(input).unwrap(); let (vis, ty, generics) = (&ast.vis, &ast.ident, &ast.generics); let names_struct_ident = Ident::new(&(ty.to_string() + "FieldStaticStr"), Span::call_site()); diff --git a/actix_admin/src/lib.rs b/actix_admin/src/lib.rs index d8640b3..3270dbe 100644 --- a/actix_admin/src/lib.rs +++ b/actix_admin/src/lib.rs @@ -1,22 +1,17 @@ -use actix_web::error::ErrorBadRequest; -use actix_web::{dev, App, FromRequest, Route}; -use actix_web::{error, guard, web, Error, HttpRequest, HttpResponse}; -use futures::future::{err, ok, Ready}; +use actix_web::{error, web, Error, HttpRequest, HttpResponse}; use lazy_static::lazy_static; -use sea_orm::DatabaseConnection; -use sea_orm::EntityTrait; -use sea_orm::ModelTrait; +use sea_orm::{ DatabaseConnection, ModelTrait, ConnectionTrait}; use serde::{Deserialize, Serialize}; -use std::any::Any; use std::collections::HashMap; -use std::pin::Pin; +use actix_web::http::header; use tera::{Context, Tera}; +use std::any::Any; use async_trait::async_trait; pub use actix_admin_macros::DeriveActixAdminModel; -const DEFAULT_POSTS_PER_PAGE: usize = 5; +const DEFAULT_ENTITIES_PER_PAGE: usize = 5; // globals lazy_static! { @@ -28,7 +23,7 @@ lazy_static! { #[derive(Debug, Deserialize)] pub struct Params { page: Option, - posts_per_page: Option, + entities_per_page: Option, } // Fields @@ -47,7 +42,7 @@ pub trait AppDataTrait { #[async_trait] pub trait ActixAdminModelTrait: Clone { async fn list_db(db: &DatabaseConnection, page: usize, posts_per_page: usize) -> Vec<&str>; - fn get_fields() -> Vec<(&'static str, ActixAdminField)>; + fn get_fields() -> Vec<(String, ActixAdminField)>; } #[derive(Clone, Debug, Serialize)] @@ -58,14 +53,15 @@ pub struct ActixAdminModel { // ActixAdminViewModel #[async_trait(?Send)] pub trait ActixAdminViewModelTrait { - async fn list(req: HttpRequest, data: web::Data) -> Result; - + async fn list(req: HttpRequest, data: web::Data) -> Result; + async fn create_get(req: HttpRequest, data: web::Data) -> Result; + async fn create_post(req: HttpRequest, data: web::Data, post_form: web::Form) -> Result; } #[derive(Clone, Debug, Serialize)] pub struct ActixAdminViewModel { pub entity_name: String, - pub fields: Vec<(&'static str, ActixAdminField)>, + pub fields: Vec<(String, ActixAdminField)>, } // ActixAdminController @@ -89,7 +85,6 @@ impl ActixAdmin { pub fn create_scope(&self) -> actix_web::Scope { let scope = web::scope("/admin").route("/", web::get().to(index::)); - scope } } @@ -110,23 +105,38 @@ pub fn list_model(req: HttpRequest, data: &web::Data, view_m let params = web::Query::::from_query(req.query_string()).unwrap(); let page = params.page.unwrap_or(1); - let posts_per_page = params.posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE); - - let columns: Vec = Vec::new(); + let entities_per_page = params.entities_per_page.unwrap_or(DEFAULT_ENTITIES_PER_PAGE); let entities: Vec<&str> = Vec::new(); // view_model.get_entities() let mut ctx = Context::new(); ctx.insert("entity_names", &entity_names); - ctx.insert("posts", &entities); + ctx.insert("entities", &entities); ctx.insert("page", &page); - ctx.insert("posts_per_page", &posts_per_page); + ctx.insert("entities_per_page", &entities_per_page); ctx.insert("num_pages", "5" /*&num_pages*/); - ctx.insert("columns", &columns); - ctx.insert("model_fields", &view_model.fields); + ctx.insert("view_model", &view_model); let body = TERA .render("list.html", &ctx) .map_err(|err| error::ErrorInternalServerError(err))?; Ok(HttpResponse::Ok().content_type("text/html").body(body)) +} + +pub fn create_get_model(req: HttpRequest, data: &web::Data, view_model: ActixAdminViewModel, entity_names: &Vec) -> Result { + let mut ctx = Context::new(); + ctx.insert("entity_names", &entity_names); + ctx.insert("view_model", &view_model); + ctx.insert("model_fields", &view_model.fields); + + let body = TERA + .render("create.html", &ctx) + .map_err(|err| error::ErrorInternalServerError(err))?; + Ok(HttpResponse::Ok().content_type("text/html").body(body)) +} + +pub fn create_post_model(req: HttpRequest, data: &web::Data, view_model: ActixAdminViewModel) -> Result { + Ok(HttpResponse::Found() + .append_header((header::LOCATION, format!("/admin/{}/list", view_model.entity_name))) + .finish()) } \ No newline at end of file diff --git a/actix_admin/templates/create.html b/actix_admin/templates/create.html new file mode 100644 index 0000000..0572d5c --- /dev/null +++ b/actix_admin/templates/create.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block content %} +
+
+ {% for model_field in view_model.fields -%} + + {%- endfor %} + +
+
+{% endblock content %} \ No newline at end of file diff --git a/actix_admin/templates/list.html b/actix_admin/templates/list.html index e77ee1e..3612ff2 100644 --- a/actix_admin/templates/list.html +++ b/actix_admin/templates/list.html @@ -1,9 +1,10 @@ {% extends "base.html" %} {% block content %} +Create - {% for model_field in model_fields -%} + {% for model_field in view_model.fields -%} {%- endfor %} diff --git a/database.db-wal b/database.db-wal index 9ef2d3a..9af5d47 100644 Binary files a/database.db-wal and b/database.db-wal differ diff --git a/src/entity/comment.rs b/src/entity/comment.rs index 9ab70bf..9252222 100644 --- a/src/entity/comment.rs +++ b/src/entity/comment.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use actix_admin::{ DeriveActixAdminModel }; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, DeriveActixAdminModel)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize/*, DeriveActixAdminModel*/)] #[sea_orm(table_name = "comment")] pub struct Model { #[sea_orm(primary_key)] diff --git a/src/main.rs b/src/main.rs index caa8b74..2a8542e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,17 +5,19 @@ use actix_admin::{ AppDataTrait as ActixAdminAppDataTrait, }; use actix_session::{CookieSession, Session}; -use actix_web::{web, App, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpResponse, HttpServer, middleware}; use azure_auth::{AppDataTrait as AzureAuthAppDataTrait, AzureAuth, UserInfo}; use oauth2::basic::BasicClient; use oauth2::RedirectUrl; use sea_orm::{ConnectOptions, DatabaseConnection}; +use sea_orm::{entity::*, query::*}; +use sea_orm::EntityTrait; use std::env; use std::time::Duration; use tera::{Context, Tera}; mod entity; -use entity::{Comment, Post}; +use entity::{Comment, Post, comment, post}; #[derive(Debug, Clone)] pub struct AppState { @@ -58,18 +60,23 @@ async fn index(session: Session, data: web::Data) -> HttpResponse { fn setup_actix_admin( actix_admin: &ActixAdmin, post_view_model: &ActixAdminViewModel, - comment_view_model: &ActixAdminViewModel, + //comment_view_model: &ActixAdminViewModel, ) -> actix_web::Scope { actix_admin .create_scope::() .service( web::scope(&format!("/{}", post_view_model.entity_name)) - .route("/list", web::get().to(Post::list::)), - ) - .service( - web::scope(&format!("/{}", comment_view_model.entity_name)) - .route("/list", web::get().to(Comment::list::)), + .route("/list", web::get().to(Post::list::)) + .route("/create", web::get().to(Post::create_get::)) + .route("/create", web::post().to(Post::create_post::)) + ) + // .service( + // web::scope(&format!("/{}", comment_view_model.entity_name)) + // .route("/list", web::get().to(Comment::list::)) + // .route("/create", web::get().to(Comment::create_get::)) + // .route("/create", web::post().to(Comment::create_post::)) + // ) } #[actix_rt::main] @@ -107,10 +114,11 @@ async fn main() { let _ = entity::create_post_table(&conn).await; let post_view_model = ActixAdminViewModel::from(Post); - let comment_view_model = ActixAdminViewModel::from(Comment); + //let comment_view_model = ActixAdminViewModel::from(Comment); let actix_admin = ActixAdmin::new() .add_entity::(&post_view_model) - .add_entity::(&comment_view_model); + //.add_entity::(&comment_view_model) + ; let app_state = AppState { oauth: client, tmpl: tera, @@ -127,8 +135,9 @@ async fn main() { .service(setup_actix_admin( &actix_admin, &post_view_model, - &comment_view_model, + //&comment_view_model, )) + .wrap(middleware::Logger::default()) }) .bind("127.0.0.1:5000") .expect("Can not bind to port 5000") diff --git a/templates/base.html b/templates/base.html index 0384afe..54adadc 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,7 +4,7 @@ Actix Web - +
{{ model_field[0] }}