add create fn
This commit is contained in:
parent
790cf9ff59
commit
60797bd9eb
@ -1,14 +1,12 @@
|
||||
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();
|
||||
@ -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<Entity> for ActixAdminViewModel {
|
||||
fn from(entity: Entity) -> Self {
|
||||
@ -35,14 +37,38 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
||||
#[async_trait(?Send)]
|
||||
impl ActixAdminViewModelTrait for Entity {
|
||||
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);
|
||||
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<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error> {
|
||||
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<T: AppDataTrait, M>(req: HttpRequest, data: web::Data<T>, post_form: web::Form<M>) -> Result<HttpResponse, Error> {
|
||||
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,11 +82,10 @@ 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!(
|
||||
#(#names_const_fields_str),*
|
||||
@ -69,8 +94,11 @@ pub fn derive_crud_fns(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
|
||||
.into_iter()
|
||||
.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
|
||||
)
|
||||
)
|
||||
|
@ -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());
|
||||
|
@ -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<usize>,
|
||||
posts_per_page: Option<usize>,
|
||||
entities_per_page: Option<usize>,
|
||||
}
|
||||
|
||||
// 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<T: AppDataTrait + Sync + Send>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error>;
|
||||
|
||||
async fn list<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error>;
|
||||
async fn create_get<T: AppDataTrait>(req: HttpRequest, data: web::Data<T>) -> Result<HttpResponse, Error>;
|
||||
async fn create_post<T: AppDataTrait, M>(req: HttpRequest, data: web::Data<T>, post_form: web::Form<M>) -> Result<HttpResponse, Error>;
|
||||
}
|
||||
|
||||
#[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<T: AppDataTrait + 'static>(&self) -> actix_web::Scope {
|
||||
let scope = web::scope("/admin").route("/", web::get().to(index::<T>));
|
||||
|
||||
scope
|
||||
}
|
||||
}
|
||||
@ -110,23 +105,38 @@ pub fn list_model<T: AppDataTrait>(req: HttpRequest, data: &web::Data<T>, view_m
|
||||
let params = web::Query::<Params>::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<String> = 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<T: AppDataTrait>(req: HttpRequest, data: &web::Data<T>, view_model: ActixAdminViewModel, entity_names: &Vec<String>) -> Result<HttpResponse, Error> {
|
||||
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<T: AppDataTrait>(req: HttpRequest, data: &web::Data<T>, view_model: ActixAdminViewModel) -> Result<HttpResponse, Error> {
|
||||
Ok(HttpResponse::Found()
|
||||
.append_header((header::LOCATION, format!("/admin/{}/list", view_model.entity_name)))
|
||||
.finish())
|
||||
}
|
12
actix_admin/templates/create.html
Normal file
12
actix_admin/templates/create.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
<div class="grid">
|
||||
{% for model_field in view_model.fields -%}
|
||||
<input type="text" name="{{ model_field[0] }}" placeholder="{{ model_field[0] }}" aria-label="{{ model_field[0] }}"><!-- required="" -->
|
||||
{%- endfor %}
|
||||
<button type="submit">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
@ -1,9 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<a href="create" role="button">Create</a>
|
||||
<table>
|
||||
<tr>
|
||||
{% for model_field in model_fields -%}
|
||||
{% for model_field in view_model.fields -%}
|
||||
<th>{{ model_field[0] }}</th>
|
||||
{%- endfor %}
|
||||
</tr>
|
||||
|
BIN
database.db-wal
BIN
database.db-wal
Binary file not shown.
@ -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)]
|
||||
|
31
src/main.rs
31
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<AppState>) -> 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::<AppState>()
|
||||
.service(
|
||||
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>)),
|
||||
.route("/list", web::get().to(Post::list::<AppState>))
|
||||
.route("/create", web::get().to(Post::create_get::<AppState>))
|
||||
.route("/create", web::post().to(Post::create_post::<AppState, post::Model>))
|
||||
|
||||
)
|
||||
// .service(
|
||||
// web::scope(&format!("/{}", comment_view_model.entity_name))
|
||||
// .route("/list", web::get().to(Comment::list::<AppState>))
|
||||
// .route("/create", web::get().to(Comment::create_get::<AppState>))
|
||||
// .route("/create", web::post().to(Comment::create_post::<AppState, comment::Model>))
|
||||
// )
|
||||
}
|
||||
|
||||
#[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::<AppState>(&post_view_model)
|
||||
.add_entity::<AppState>(&comment_view_model);
|
||||
//.add_entity::<AppState>(&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")
|
||||
|
@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Actix Web</title>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.classless.min.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
Loading…
Reference in New Issue
Block a user