add custom handlers & post integration test
This commit is contained in:
parent
920c5d00aa
commit
a7352e5793
@ -7,6 +7,7 @@ use azure_auth::{AppDataTrait as AzureAuthAppDataTrait, AzureAuth, UserInfo};
|
||||
use oauth2::basic::BasicClient;
|
||||
use oauth2::RedirectUrl;
|
||||
use sea_orm::{ConnectOptions, DatabaseConnection};
|
||||
use actix_web::http::header::ContentType;
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
use tera::{Context, Tera};
|
||||
@ -37,6 +38,19 @@ impl AzureAuthAppDataTrait for AppState {
|
||||
}
|
||||
}
|
||||
|
||||
async fn custom_handler<
|
||||
T: ActixAdminAppDataTrait,
|
||||
E: ActixAdminViewModelTrait,
|
||||
>(
|
||||
_session: Session,
|
||||
_data: web::Data<T>,
|
||||
_text: String
|
||||
) -> HttpResponse {
|
||||
HttpResponse::Ok()
|
||||
.content_type(ContentType::plaintext())
|
||||
.body("data")
|
||||
}
|
||||
|
||||
async fn index(session: Session, data: web::Data<AppState>) -> HttpResponse {
|
||||
let login = session.get::<UserInfo>("user_info").unwrap();
|
||||
let web_auth_link = if login.is_some() {
|
||||
@ -62,12 +76,16 @@ fn create_actix_admin_builder() -> ActixAdminBuilder {
|
||||
user_info.is_some()
|
||||
}),
|
||||
login_link: Some("/azure-auth/login".to_string()),
|
||||
logout_link: Some("/azure-auth/logout".to_string()
|
||||
logout_link: Some("/azure-auth/logout".to_string())
|
||||
};
|
||||
|
||||
let mut admin_builder = ActixAdminBuilder::new(configuration);
|
||||
admin_builder.add_entity::<AppState, Post>(&post_view_model);
|
||||
admin_builder.add_entity::<AppState, Comment>(&comment_view_model);
|
||||
admin_builder.add_custom_handler_for_entity::<AppState, Comment>(
|
||||
"/custom_handler",
|
||||
web::get().to(custom_handler::<AppState, Comment>)
|
||||
);
|
||||
|
||||
admin_builder
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use actix_web::web;
|
||||
use actix_web::{ web, Route };
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::prelude::*;
|
||||
@ -6,7 +6,7 @@ use crate::prelude::*;
|
||||
use crate::routes::{create_get, create_post, delete, delete_many, edit_get, edit_post, index, list};
|
||||
|
||||
pub struct ActixAdminBuilder {
|
||||
pub scopes: Vec<actix_web::Scope>,
|
||||
pub scopes: HashMap<String, actix_web::Scope>,
|
||||
pub actix_admin: ActixAdmin,
|
||||
}
|
||||
|
||||
@ -16,6 +16,11 @@ pub trait ActixAdminBuilderTrait {
|
||||
&mut self,
|
||||
view_model: &ActixAdminViewModel,
|
||||
);
|
||||
fn add_custom_handler_for_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
|
||||
&mut self,
|
||||
path: &str,
|
||||
route: Route
|
||||
);
|
||||
fn get_scope<T: ActixAdminAppDataTrait + 'static>(self) -> actix_web::Scope;
|
||||
fn get_actix_admin(&self) -> ActixAdmin;
|
||||
}
|
||||
@ -28,7 +33,7 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
view_models: HashMap::new(),
|
||||
configuration: configuration
|
||||
},
|
||||
scopes: Vec::new(),
|
||||
scopes: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +41,8 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
&mut self,
|
||||
view_model: &ActixAdminViewModel,
|
||||
) {
|
||||
self.scopes.push(
|
||||
self.scopes.insert(
|
||||
E::get_entity_name(),
|
||||
web::scope(&format!("/{}", E::get_entity_name()))
|
||||
.route("/list", web::get().to(list::<T, E>))
|
||||
.route("/create", web::get().to(create_get::<T, E>))
|
||||
@ -52,13 +58,38 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
self.actix_admin.view_models.insert(key, view_model.clone());
|
||||
}
|
||||
|
||||
fn get_scope<T: ActixAdminAppDataTrait + '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);
|
||||
fn add_custom_handler_for_entity<T: ActixAdminAppDataTrait + 'static, E: ActixAdminViewModelTrait + 'static>(
|
||||
&mut self,
|
||||
path: &str,
|
||||
route: Route
|
||||
) {
|
||||
let existing_scope = self.scopes.remove(&E::get_entity_name());
|
||||
match existing_scope {
|
||||
Some(scope) => {
|
||||
let existing_scope = scope.route(path, route);
|
||||
self.scopes.insert(E::get_entity_name(), existing_scope);
|
||||
},
|
||||
_ => {
|
||||
let new_scope =
|
||||
web::scope(&format!("/{}", E::get_entity_name()))
|
||||
.route(path, route);
|
||||
self.scopes.insert(E::get_entity_name(), new_scope);
|
||||
}
|
||||
}
|
||||
|
||||
if !self.actix_admin.entity_names.contains(&E::get_entity_name()) {
|
||||
self.actix_admin.entity_names.push(E::get_entity_name());
|
||||
}
|
||||
}
|
||||
|
||||
fn get_scope<T: ActixAdminAppDataTrait + 'static>(mut self) -> actix_web::Scope {
|
||||
let mut admin_scope = web::scope("/admin").route("/", web::get().to(index::<T>));
|
||||
for entity_name in self.actix_admin.entity_names {
|
||||
let scope = self.scopes.remove(&entity_name).unwrap();
|
||||
admin_scope = admin_scope.service(scope);
|
||||
}
|
||||
|
||||
scope
|
||||
admin_scope
|
||||
}
|
||||
|
||||
fn get_actix_admin(&self) -> ActixAdmin {
|
||||
|
@ -18,6 +18,7 @@ pub mod prelude {
|
||||
pub use actix_admin_macros::{ DeriveActixAdmin, DeriveActixAdminModel, DeriveActixAdminViewModel, DeriveActixAdminEnumSelectList, DeriveActixAdminModelSelectList };
|
||||
pub use crate::{ ActixAdminAppDataTrait, ActixAdmin, ActixAdminConfiguration };
|
||||
pub use crate::{ hashmap, ActixAdminSelectListTrait };
|
||||
pub use crate::routes::{ create_or_edit_post };
|
||||
}
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -1,30 +1,38 @@
|
||||
use actix_web::http::header;
|
||||
use actix_web::{web, error, Error, HttpResponse};
|
||||
use tera::{Context};
|
||||
use actix_session::{Session};
|
||||
use crate::TERA;
|
||||
use actix_multipart::Multipart;
|
||||
use super::{ user_can_access_page, render_unauthorized};
|
||||
use super::{render_unauthorized, user_can_access_page};
|
||||
use crate::prelude::*;
|
||||
use crate::TERA;
|
||||
use actix_session::Session;
|
||||
use actix_web::http::header;
|
||||
use actix_web::{error, web, Error, HttpResponse};
|
||||
use tera::Context;
|
||||
use actix_multipart::Multipart;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub async fn create_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
session: Session,
|
||||
data: web::Data<T>,
|
||||
payload: Multipart,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
create_or_edit_post::<T, E>(&session, &data, payload, None).await
|
||||
let model = ActixAdminModel::create_from_payload(payload).await.unwrap();
|
||||
create_or_edit_post::<T, E>(&session, &data, model, None).await
|
||||
}
|
||||
|
||||
pub async fn edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
session: Session,
|
||||
data: web::Data<T>,
|
||||
payload: Multipart,
|
||||
id: web::Path<i32>
|
||||
id: web::Path<i32>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
create_or_edit_post::<T, E>(&session, &data, payload, Some(id.into_inner())).await
|
||||
let model = ActixAdminModel::create_from_payload(payload).await.unwrap();
|
||||
create_or_edit_post::<T, E>(&session, &data, model, Some(id.into_inner())).await
|
||||
}
|
||||
|
||||
async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(session: &Session, data: &web::Data<T>, payload: Multipart, id: Option<i32>) -> Result<HttpResponse, Error> {
|
||||
pub async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
session: &Session,
|
||||
data: &web::Data<T>,
|
||||
mut model: ActixAdminModel,
|
||||
id: Option<i32>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let actix_admin = data.get_actix_admin();
|
||||
let entity_name = E::get_entity_name();
|
||||
|
||||
@ -35,15 +43,16 @@ async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTr
|
||||
ctx.insert("render_partial", &true);
|
||||
return render_unauthorized(&ctx);
|
||||
}
|
||||
|
||||
let db = &data.get_db();
|
||||
let mut model = ActixAdminModel::create_from_payload(payload).await.unwrap();
|
||||
E::validate_entity(&mut model);
|
||||
|
||||
if model.has_errors() {
|
||||
let mut ctx = Context::new();
|
||||
ctx.insert("entity_names", &actix_admin.entity_names);
|
||||
ctx.insert("view_model", &ActixAdminViewModelSerializable::from(view_model.clone()));
|
||||
ctx.insert(
|
||||
"view_model",
|
||||
&ActixAdminViewModelSerializable::from(view_model.clone()),
|
||||
);
|
||||
ctx.insert("select_lists", &E::get_select_lists(db).await);
|
||||
ctx.insert("list_link", &E::get_list_link(&entity_name));
|
||||
ctx.insert("model", &model);
|
||||
@ -52,11 +61,10 @@ async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTr
|
||||
.render("create_or_edit.html", &ctx)
|
||||
.map_err(|err| error::ErrorInternalServerError(err))?;
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(body))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
match id {
|
||||
Some(id) => E::edit_entity(db, id, model).await,
|
||||
None => E::create_entity(db, model).await
|
||||
None => E::create_entity(db, model).await,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::SeeOther()
|
||||
@ -65,5 +73,29 @@ async fn create_or_edit_post<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTr
|
||||
format!("/admin/{}/list", view_model.entity_name),
|
||||
))
|
||||
.finish())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<String> for ActixAdminModel {
|
||||
fn from(string: String) -> Self {
|
||||
let mut hashmap = HashMap::new();
|
||||
let key_values: Vec<&str> = string.split('&').collect();
|
||||
for key_value in key_values {
|
||||
if !key_value.is_empty() {
|
||||
let mut iter = key_value.splitn(2, '=');
|
||||
hashmap.insert(
|
||||
iter.next().unwrap().to_string(),
|
||||
iter.next().unwrap().to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ActixAdminModel {
|
||||
primary_key: None,
|
||||
values: hashmap,
|
||||
errors: HashMap::new(),
|
||||
custom_errors: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ mod create_or_edit_get;
|
||||
pub use create_or_edit_get::{create_get, edit_get};
|
||||
|
||||
mod create_or_edit_post;
|
||||
pub use create_or_edit_post::{ create_post, edit_post };
|
||||
pub use create_or_edit_post::{ create_post, edit_post, create_or_edit_post };
|
||||
|
||||
mod index;
|
||||
pub use index::index;
|
||||
|
@ -11,27 +11,27 @@ mod tests {
|
||||
use actix_admin::prelude::*;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_admin_index_get() {
|
||||
async fn admin_index_get() {
|
||||
test_get_is_success("/admin/").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_post_list() {
|
||||
async fn post_list_get() {
|
||||
test_get_is_success("/admin/post/list").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_comment_list() {
|
||||
async fn comment_list_get() {
|
||||
test_get_is_success("/admin/comment/list").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_post_create() {
|
||||
async fn post_create_get() {
|
||||
test_get_is_success("/admin/post/create").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_comment_create() {
|
||||
async fn comment_create_get() {
|
||||
test_get_is_success("/admin/comment/create").await
|
||||
}
|
||||
|
||||
|
60
tests/integration_test_post_resp_is_success.rs
Normal file
60
tests/integration_test_post_resp_is_success.rs
Normal file
@ -0,0 +1,60 @@
|
||||
mod test_setup;
|
||||
use test_setup::helper::{create_actix_admin_builder, create_tables_and_get_connection, AppState};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate serde_derive;
|
||||
|
||||
use actix_admin::prelude::*;
|
||||
use actix_web::http::header::ContentType;
|
||||
use actix_web::test;
|
||||
use actix_web::{middleware, web, App};
|
||||
|
||||
#[actix_web::test]
|
||||
async fn comment_create_post() {
|
||||
test_post_is_success("/admin/comment/create_post_from_plaintext").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn post_create_post() {
|
||||
test_post_is_success("/admin/post/create_post_from_plaintext").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn post_edit_post() {
|
||||
test_post_is_success("/admin/post/edit_post_from_plaintext").await
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn comment_edit_post() {
|
||||
test_post_is_success("/admin/comment/edit_post_from_plaintext").await
|
||||
}
|
||||
|
||||
async fn test_post_is_success(url: &str) {
|
||||
let conn = super::create_tables_and_get_connection().await;
|
||||
|
||||
let actix_admin_builder = super::create_actix_admin_builder();
|
||||
let actix_admin = actix_admin_builder.get_actix_admin();
|
||||
|
||||
let app_state = super::AppState {
|
||||
db: conn,
|
||||
actix_admin: actix_admin,
|
||||
};
|
||||
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state.clone()))
|
||||
.service(actix_admin_builder.get_scope::<super::AppState>())
|
||||
.wrap(middleware::Logger::default()),
|
||||
)
|
||||
.await;
|
||||
|
||||
let req = test::TestRequest::post()
|
||||
.insert_header(ContentType::form_url_encoded())
|
||||
.uri(url)
|
||||
.to_request();
|
||||
let resp = test::call_service(&app, req).await;
|
||||
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
use sea_orm::{ConnectOptions, DatabaseConnection};
|
||||
use actix_admin::prelude::*;
|
||||
use actix_web::Error;
|
||||
use actix_session::Session;
|
||||
use actix_web::HttpResponse;
|
||||
use actix_web::{web};
|
||||
|
||||
use super::{Post, Comment, create_tables};
|
||||
|
||||
@ -43,5 +47,47 @@ pub fn create_actix_admin_builder() -> ActixAdminBuilder {
|
||||
admin_builder.add_entity::<AppState, Post>(&post_view_model);
|
||||
admin_builder.add_entity::<AppState, Comment>(&comment_view_model);
|
||||
|
||||
admin_builder.add_custom_handler_for_entity::<AppState, Comment>(
|
||||
"/create_comment_from_plaintext",
|
||||
web::post().to(create_post_from_plaintext::<AppState, Comment>));
|
||||
|
||||
admin_builder.add_custom_handler_for_entity::<AppState, Post>(
|
||||
"/create_post_from_plaintext",
|
||||
web::post().to(create_post_from_plaintext::<AppState, Post>));
|
||||
|
||||
admin_builder.add_custom_handler_for_entity::<AppState, Post>(
|
||||
"/edit_post_from_plaintext/{id}",
|
||||
web::post().to(edit_post_from_plaintext::<AppState, Post>));
|
||||
|
||||
admin_builder.add_custom_handler_for_entity::<AppState, Comment>(
|
||||
"/edit_comment_from_plaintext/{id}",
|
||||
web::post().to(edit_post_from_plaintext::<AppState, Comment>));
|
||||
|
||||
admin_builder
|
||||
}
|
||||
|
||||
async fn create_post_from_plaintext<
|
||||
T: ActixAdminAppDataTrait,
|
||||
E: ActixAdminViewModelTrait,
|
||||
>(
|
||||
session: Session,
|
||||
data: web::Data<T>,
|
||||
text: String,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let model = ActixAdminModel::from(text);
|
||||
create_or_edit_post::<T, E>(&session, &data, model, None).await
|
||||
}
|
||||
|
||||
async fn edit_post_from_plaintext<
|
||||
T: ActixAdminAppDataTrait,
|
||||
E: ActixAdminViewModelTrait,
|
||||
>(
|
||||
session: Session,
|
||||
data: web::Data<T>,
|
||||
text: String,
|
||||
id: web::Path<i32>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
println!("ok");
|
||||
let model = ActixAdminModel::from(text);
|
||||
create_or_edit_post::<T, E>(&session, &data, model, Some(id.into_inner())).await
|
||||
}
|
Loading…
Reference in New Issue
Block a user