serve static files via actix_files
This commit is contained in:
parent
1e916d1238
commit
f4571721e5
@ -1,4 +1,4 @@
|
||||
use crate::{prelude::*, ActixAdminMenuElement, routes::delete_static_content};
|
||||
use crate::{prelude::*, ActixAdminMenuElement, routes::delete_file};
|
||||
use actix_web::{web, Route};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
@ -102,8 +102,8 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
.route("/delete", web::delete().to(delete_many::<T, E>))
|
||||
.route("/delete/{id}", web::delete().to(delete::<T, E>))
|
||||
.route("/show/{id}", web::get().to(show::<T, E>))
|
||||
.route("/static_content/{id}/{column_name}", web::get().to(download::<T, E>))
|
||||
.route("/static_content/{id}/{column_name}", web::delete().to(delete_static_content::<T, E>))
|
||||
.route("/file/{id}/{column_name}", web::get().to(download::<T, E>))
|
||||
.route("/file/{id}/{column_name}", web::delete().to(delete_file::<T, E>))
|
||||
.default_service(web::to(not_found))
|
||||
);
|
||||
|
||||
@ -232,6 +232,7 @@ impl ActixAdminBuilderTrait for ActixAdminBuilder {
|
||||
};
|
||||
let mut admin_scope = web::scope("/admin")
|
||||
.route("/", index_handler)
|
||||
.service(actix_files::Files::new("/static", "./static").show_files_listing())
|
||||
.default_service(web::to(not_found));
|
||||
|
||||
for (_entity, scope) in self.scopes {
|
||||
|
@ -1,16 +1,16 @@
|
||||
use actix_web::{web, Error, HttpRequest, HttpResponse};
|
||||
use super::{render_unauthorized, user_can_access_page};
|
||||
use crate::prelude::*;
|
||||
use actix_session::Session;
|
||||
use actix_web::http::header;
|
||||
use actix_session::{Session};
|
||||
use crate::{prelude::*};
|
||||
use tera::{Context};
|
||||
use super::{ user_can_access_page, render_unauthorized};
|
||||
use actix_web::{web, Error, HttpRequest, HttpResponse};
|
||||
use tera::Context;
|
||||
|
||||
pub async fn delete<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
session: Session,
|
||||
_req: HttpRequest,
|
||||
data: web::Data<T>,
|
||||
_text: String,
|
||||
id: web::Path<i32>
|
||||
id: web::Path<i32>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let actix_admin = data.get_actix_admin();
|
||||
let entity_name = E::get_entity_name();
|
||||
@ -32,16 +32,25 @@ pub async fn delete<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
(Ok(model), Ok(_)) => {
|
||||
for field in view_model.fields {
|
||||
if field.field_type == ActixAdminViewModelFieldType::FileUpload {
|
||||
let file_name = model.get_value::<String>(&field.field_name, true, true).unwrap_or_default();
|
||||
let file_path = format!("{}/{}/{}", actix_admin.configuration.file_upload_directory, E::get_entity_name(), file_name.unwrap_or_default());
|
||||
std::fs::remove_file(file_path)?;
|
||||
let file_name = model
|
||||
.get_value::<String>(&field.field_name, true, true)
|
||||
.unwrap_or_default();
|
||||
if file_name.is_some() {
|
||||
let file_path = format!(
|
||||
"{}/{}/{}",
|
||||
actix_admin.configuration.file_upload_directory,
|
||||
E::get_entity_name(),
|
||||
file_name.unwrap()
|
||||
);
|
||||
std::fs::remove_file(file_path)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().finish())
|
||||
},
|
||||
(_,_) => Ok(HttpResponse::InternalServerError().finish())
|
||||
}
|
||||
}
|
||||
(_, _) => Ok(HttpResponse::InternalServerError().finish()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(
|
||||
@ -61,15 +70,15 @@ pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
||||
ctx.insert("render_partial", &true);
|
||||
return render_unauthorized(&ctx);
|
||||
}
|
||||
|
||||
|
||||
let db = &data.get_db();
|
||||
let entity_name = E::get_entity_name();
|
||||
let entity_ids: Vec<i32> = text
|
||||
.split("&")
|
||||
.filter(|id| !id.is_empty())
|
||||
.map(|id_str| id_str.replace("ids=", "").parse::<i32>().unwrap()
|
||||
).collect();
|
||||
|
||||
.map(|id_str| id_str.replace("ids=", "").parse::<i32>().unwrap())
|
||||
.collect();
|
||||
|
||||
// TODO: implement delete_many
|
||||
for id in entity_ids {
|
||||
let model_result = E::get_entity(db, id).await;
|
||||
@ -79,27 +88,30 @@ pub async fn delete_many<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>
|
||||
(Ok(_), Ok(model)) => {
|
||||
for field in view_model.fields {
|
||||
if field.field_type == ActixAdminViewModelFieldType::FileUpload {
|
||||
let file_name = model.get_value::<String>(&field.field_name, true, true).unwrap_or_default();
|
||||
let file_path = format!("{}/{}/{}", actix_admin.configuration.file_upload_directory, E::get_entity_name(), file_name.unwrap_or_default());
|
||||
let file_name = model
|
||||
.get_value::<String>(&field.field_name, true, true)
|
||||
.unwrap_or_default();
|
||||
let file_path = format!(
|
||||
"{}/{}/{}",
|
||||
actix_admin.configuration.file_upload_directory,
|
||||
E::get_entity_name(),
|
||||
file_name.unwrap_or_default()
|
||||
);
|
||||
std::fs::remove_file(file_path)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
(Ok(_), Err(e)) => errors.push(e)
|
||||
}
|
||||
(Ok(_), Err(e)) => errors.push(e),
|
||||
}
|
||||
}
|
||||
|
||||
match errors.is_empty() {
|
||||
true => {
|
||||
Ok(HttpResponse::SeeOther()
|
||||
true => Ok(HttpResponse::SeeOther()
|
||||
.append_header((
|
||||
header::LOCATION,
|
||||
format!("/admin/{}/list?render_partial=true", entity_name),
|
||||
))
|
||||
.finish())
|
||||
},
|
||||
false => {
|
||||
Ok(HttpResponse::InternalServerError().finish())
|
||||
}
|
||||
.finish()),
|
||||
false => Ok(HttpResponse::InternalServerError().finish()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ pub async fn download<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(re
|
||||
|
||||
}
|
||||
|
||||
pub async fn delete_static_content<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(session: Session, data: web::Data<T>, params: web::Path<(i32, String)>) -> Result<HttpResponse, Error> {
|
||||
pub async fn delete_file<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(session: Session, data: web::Data<T>, params: web::Path<(i32, String)>) -> Result<HttpResponse, Error> {
|
||||
let actix_admin = data.get_actix_admin();
|
||||
let db = &data.get_db();
|
||||
|
@ -19,5 +19,5 @@ pub use delete::{ delete, delete_many };
|
||||
mod helpers;
|
||||
pub use helpers::{ add_auth_context, user_can_access_page, render_unauthorized };
|
||||
|
||||
mod static_content;
|
||||
pub use static_content::{download, delete_static_content};
|
||||
mod file;
|
||||
pub use file::{download, delete_file};
|
@ -50,6 +50,6 @@ pub async fn show<T: ActixAdminAppDataTrait, E: ActixAdminViewModelTrait>(sessio
|
||||
|
||||
let body = TERA
|
||||
.render("show.html", &ctx)
|
||||
.map_err(|_| error::ErrorInternalServerError("Template error"))?;
|
||||
.map_err(|err| error::ErrorInternalServerError(format!("{:?}", err)))?;
|
||||
Ok(http_response_code.content_type("text/html").body(body))
|
||||
}
|
12
static/css/default.css
Normal file
12
static/css/default.css
Normal file
@ -0,0 +1,12 @@
|
||||
.loader-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
align-items: center;
|
||||
z-index: 6;
|
||||
pointer-events: none
|
||||
}
|
68
static/js/default.js
Normal file
68
static/js/default.js
Normal file
@ -0,0 +1,68 @@
|
||||
document.onkeydown = function (e) {
|
||||
switch (e.which) {
|
||||
case 37: // left
|
||||
let left_el = document.getElementsByClassName('left-arrow-click').item(0);
|
||||
if (left_el) { left_el.click(); };
|
||||
break;
|
||||
|
||||
//case 38: // up
|
||||
// break;
|
||||
|
||||
case 39: // right
|
||||
let right_el = document.getElementsByClassName('right-arrow-click').item(0);
|
||||
if (right_el) { right_el.click(); };
|
||||
break;
|
||||
|
||||
//case 40: // down
|
||||
// break;
|
||||
|
||||
default: return; // exit this handler for other keys
|
||||
}
|
||||
e.preventDefault(); // prevent the default action (scroll / move caret)
|
||||
};
|
||||
|
||||
function checkAll(bx) {
|
||||
var cbs = document.getElementsByTagName('input');
|
||||
for (var i = 0; i < cbs.length; i++) {
|
||||
if (cbs[i].type == 'checkbox') {
|
||||
cbs[i].checked = bx.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sort_by(column) {
|
||||
document.getElementById("sort_by").value = column;
|
||||
current_sort_order = document.getElementById("sort_order").value;
|
||||
if (current_sort_order == "{{ sort_order_asc }}") {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_desc }}";
|
||||
} else {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_asc }}";
|
||||
}
|
||||
document.getElementById('search_form').submit();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Get all "navbar-burger" elements
|
||||
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
|
||||
|
||||
// Add a click event on each of them
|
||||
$navbarBurgers.forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
|
||||
// Get the target from the "data-target" attribute
|
||||
const target = el.dataset.target;
|
||||
const $target = document.getElementById(target);
|
||||
|
||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||
el.classList.toggle('is-active');
|
||||
$target.classList.toggle('is-active');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
htmx.on("htmx:responseError", function () {
|
||||
document.getElementById("notifications").insertAdjacentHTML(
|
||||
"afterend",
|
||||
"<div class=\"notification mb-4 is-light is-danger\"><button class=\"delete\" onclick=\"this.parentElement.remove()\"></button>An Error occurred</div>");
|
||||
})
|
@ -12,9 +12,9 @@
|
||||
aria-label="{{ model_field.field_name }}">{{ model.values | get(key=model_field.field_name, default="") }}</textarea>
|
||||
{% elif model_field.field_type == "FileUpload" and model.values | get(key=model_field.field_name, default="") != "" %}
|
||||
<div>
|
||||
<a hx-disable href="{{ base_path }}/static_content/{{ model.primary_key }}/{{ model_field.field_name }}">{{ model.values |
|
||||
<a hx-disable href="{{ base_path }}/file/{{ model.primary_key }}/{{ model_field.field_name }}">{{ model.values |
|
||||
get(key=model_field.field_name, default="") }}</a>
|
||||
<a class="is-pulled-right" hx-target="closest div" hx-push-url="false" hx-delete="{{ base_path }}/static_content/{{ model.primary_key }}/{{ model_field.field_name }}"
|
||||
<a class="is-pulled-right" hx-target="closest div" hx-push-url="false" hx-delete="{{ base_path }}/file/{{ model.primary_key }}/{{ model_field.field_name }}"
|
||||
hx-confirm="Are you sure?"><i class="fa-solid fa-trash"></i></a>
|
||||
</div>
|
||||
{% else %}
|
||||
|
@ -6,90 +6,5 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.8.4"></script>
|
||||
|
||||
{% raw %}
|
||||
<script>
|
||||
document.onkeydown = function (e) {
|
||||
switch (e.which) {
|
||||
case 37: // left
|
||||
let left_el = document.getElementsByClassName('left-arrow-click').item(0);
|
||||
if (left_el) { left_el.click(); };
|
||||
break;
|
||||
|
||||
//case 38: // up
|
||||
// break;
|
||||
|
||||
case 39: // right
|
||||
let right_el = document.getElementsByClassName('right-arrow-click').item(0);
|
||||
if (right_el) { right_el.click(); };
|
||||
break;
|
||||
|
||||
//case 40: // down
|
||||
// break;
|
||||
|
||||
default: return; // exit this handler for other keys
|
||||
}
|
||||
e.preventDefault(); // prevent the default action (scroll / move caret)
|
||||
};
|
||||
|
||||
function checkAll(bx) {
|
||||
var cbs = document.getElementsByTagName('input');
|
||||
for (var i = 0; i < cbs.length; i++) {
|
||||
if (cbs[i].type == 'checkbox') {
|
||||
cbs[i].checked = bx.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sort_by(column) {
|
||||
document.getElementById("sort_by").value = column;
|
||||
current_sort_order = document.getElementById("sort_order").value;
|
||||
if (current_sort_order == "{{ sort_order_asc }}") {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_desc }}";
|
||||
} else {
|
||||
document.getElementById("sort_order").value = "{{ sort_order_asc }}";
|
||||
}
|
||||
document.getElementById('search_form').submit();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Get all "navbar-burger" elements
|
||||
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
|
||||
|
||||
// Add a click event on each of them
|
||||
$navbarBurgers.forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
|
||||
// Get the target from the "data-target" attribute
|
||||
const target = el.dataset.target;
|
||||
const $target = document.getElementById(target);
|
||||
|
||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||
el.classList.toggle('is-active');
|
||||
$target.classList.toggle('is-active');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
htmx.on("htmx:responseError", function () {
|
||||
document.getElementById("notifications").insertAdjacentHTML(
|
||||
"afterend",
|
||||
"<div class=\"notification mb-4 is-light is-danger\"><button class=\"delete\" onclick=\"this.parentElement.remove()\"></button>An Error occurred</div>");
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.loader-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
align-items: center;
|
||||
z-index: 6;
|
||||
pointer-events: none
|
||||
}
|
||||
</style>
|
||||
{% endraw %}
|
||||
<link rel="stylesheet" href="/admin/static/css/default.css">
|
||||
<script src="/admin/static/js/default.js"></script>
|
@ -1,6 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% include "loader.html" %}
|
||||
You may customize this site by using a custom index page!
|
||||
{% endblock content %}
|
||||
|
||||
|
@ -117,7 +117,7 @@
|
||||
{% if model_field.field_type == "Checkbox" %}
|
||||
<td>{{ entity.values | get(key=model_field.field_name) | get_icon | safe }}</td>
|
||||
{% elif model_field.field_type == "FileUpload" %}
|
||||
<td><a href="static_content/{{ entity.primary_key }}/{{ model_field.field_name }}">{{
|
||||
<td><a href="file/{{ entity.primary_key }}/{{ model_field.field_name }}">{{
|
||||
entity.values
|
||||
| get(key=model_field.field_name) }}</a></td>
|
||||
{% else %}
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% if model_field.field_type == "Checkbox" %}
|
||||
<td>{{ model.values | get(key=model_field.field_name) | get_icon | safe }}</td>
|
||||
{% elif model_field.field_type == "FileUpload" %}
|
||||
<td><a href="static_content/{{ entity.primary_key }}/{{ model_field.field_name }}">{{ entity.values | get(key=model_field.field_name) }}</a></td>
|
||||
<td><a href="file/{{ view_model.primary_key }}/{{ model_field.field_name }}">{{ model.values | get(key=model_field.field_name) }}</a></td>
|
||||
{% else %}
|
||||
<td>{{ model.values | get(key=model_field.field_name) }}</td>
|
||||
{% endif %}
|
||||
|
@ -4,10 +4,10 @@ use test_setup::helper::{AppState, create_tables_and_get_connection, create_acti
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate serde_derive;
|
||||
|
||||
use actix_admin::prelude::*;
|
||||
use actix_web::test;
|
||||
use actix_web::{web, App};
|
||||
use actix_admin::prelude::*;
|
||||
use super::create_app;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn admin_index_get() {
|
||||
@ -36,27 +36,13 @@ mod tests {
|
||||
|
||||
async fn test_get_is_success(url: &str) {
|
||||
let db = 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 {
|
||||
actix_admin,
|
||||
db,
|
||||
};
|
||||
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state))
|
||||
.service(actix_admin_builder.get_scope::<super::AppState>())
|
||||
)
|
||||
.await;
|
||||
let app = create_app!(db);
|
||||
|
||||
let req = test::TestRequest::get()
|
||||
.uri(url)
|
||||
.to_request();
|
||||
let resp = test::call_service(&app, req).await;
|
||||
|
||||
assert_eq!(200, resp.status().as_u16());
|
||||
assert!(resp.status().is_success());
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ use test_setup::helper::{create_actix_admin_builder, create_tables_and_get_conne
|
||||
|
||||
#[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};
|
||||
use actix_web::{web, App};
|
||||
use chrono::NaiveDate;
|
||||
use chrono::NaiveDateTime;
|
||||
use serde::{Serialize};
|
||||
@ -16,23 +14,12 @@ mod tests {
|
||||
use sea_orm::PaginatorTrait;
|
||||
use sea_orm::prelude::Decimal;
|
||||
|
||||
use crate::create_app;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn comment_create_and_edit() {
|
||||
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,
|
||||
};
|
||||
|
||||
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 db = super::create_tables_and_get_connection().await;
|
||||
let app = create_app!(db);
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct CommentModel {
|
||||
@ -66,7 +53,7 @@ mod tests {
|
||||
assert!(resp.status().is_redirection());
|
||||
|
||||
let entities = super::test_setup::Comment::find()
|
||||
.paginate(&app_state.db, 50)
|
||||
.paginate(&db, 50)
|
||||
.fetch_page(0)
|
||||
.await
|
||||
.expect("could not retrieve entities");
|
||||
@ -98,39 +85,26 @@ mod tests {
|
||||
assert!(resp.status().is_redirection());
|
||||
|
||||
let entities = super::test_setup::Comment::find()
|
||||
.paginate(&app_state.db, 50)
|
||||
.paginate(&db, 50)
|
||||
.fetch_page(0)
|
||||
.await
|
||||
.expect("could not retrieve entities");
|
||||
|
||||
assert!(entities.len() == 1, "After edit post, db does not contain 1 model");
|
||||
assert_eq!(entities.len(), 1, "After edit post, db does not contain 1 model");
|
||||
let entity = entities.first().unwrap();
|
||||
assert!(entity.id == 1);
|
||||
assert!(entity.comment == "updated");
|
||||
assert!(entity.user == "updated");
|
||||
assert_eq!(entity.id, 1);
|
||||
assert_eq!(entity.comment, "updated");
|
||||
assert_eq!(entity.user, "updated");
|
||||
assert!(!entity.is_visible);
|
||||
assert!(entity.post_id.is_none());
|
||||
assert!(entity.my_decimal == Decimal::new(213141, 3));
|
||||
assert!(entity.insert_date == NaiveDateTime::parse_from_str("1987-04-01T14:00", "%Y-%m-%dT%H:%M").unwrap());
|
||||
assert_eq!(entity.my_decimal, Decimal::new(213141, 3));
|
||||
assert_eq!(entity.insert_date, NaiveDateTime::parse_from_str("1987-04-01T14:00", "%Y-%m-%dT%H:%M").unwrap());
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn post_create_and_edit() {
|
||||
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,
|
||||
};
|
||||
|
||||
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 db = super::create_tables_and_get_connection().await;
|
||||
let app = create_app!(db);
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct PostModel {
|
||||
@ -159,18 +133,18 @@ mod tests {
|
||||
assert!(resp.status().is_redirection());
|
||||
|
||||
let entities = super::test_setup::Post::find()
|
||||
.paginate(&app_state.db, 50)
|
||||
.paginate(&db, 50)
|
||||
.fetch_page(0)
|
||||
.await
|
||||
.expect("could not retrieve entities");
|
||||
|
||||
assert!(entities.len() == 1, "After post, db does not contain 1 model");
|
||||
assert_eq!(entities.len(), 1, "After post, db does not contain 1 model");
|
||||
let entity = entities.first().unwrap();
|
||||
assert!(entity.id == 1);
|
||||
assert!(entity.tea_mandatory == super::test_setup::post::Tea::EverydayTea);
|
||||
assert!(entity.title == model.title);
|
||||
assert!(entity.text == model.text);
|
||||
assert!(entity.insert_date == NaiveDate::parse_from_str("1977-04-01", "%Y-%m-%d").unwrap());
|
||||
assert_eq!(entity.id, 1);
|
||||
assert_eq!(entity.tea_mandatory, super::test_setup::post::Tea::EverydayTea);
|
||||
assert_eq!(entity.title, model.title);
|
||||
assert_eq!(entity.text, model.text);
|
||||
assert_eq!(entity.insert_date, NaiveDate::parse_from_str("1977-04-01", "%Y-%m-%d").unwrap());
|
||||
|
||||
// update entity
|
||||
model.tea_mandatory = "BreakfastTea";
|
||||
@ -188,16 +162,16 @@ mod tests {
|
||||
assert!(resp.status().is_redirection());
|
||||
|
||||
let entities = super::test_setup::Post::find()
|
||||
.paginate(&app_state.db, 50)
|
||||
.paginate(&db, 50)
|
||||
.fetch_page(0)
|
||||
.await
|
||||
.expect("could not retrieve entities");
|
||||
|
||||
assert!(entities.len() == 1, "After edit post, db does not contain 1 model");
|
||||
assert_eq!(entities.len(), 1, "After edit post, db does not contain 1 model");
|
||||
let entity = entities.first().unwrap();
|
||||
assert!(entity.id == 1);
|
||||
assert!(entity.text == "updated");
|
||||
assert!(entity.title == "updated");
|
||||
assert!(entity.insert_date == NaiveDate::parse_from_str("1987-04-01", "%Y-%m-%d").unwrap());
|
||||
assert_eq!(entity.id, 1);
|
||||
assert_eq!(entity.text, "updated");
|
||||
assert_eq!(entity.title, "updated");
|
||||
assert_eq!(entity.insert_date, NaiveDate::parse_from_str("1987-04-01", "%Y-%m-%d").unwrap());
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,27 @@ pub async fn create_tables_and_get_connection() -> DatabaseConnection {
|
||||
conn
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! create_app (
|
||||
($db: expr) => ({
|
||||
let conn = $db.clone();
|
||||
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,
|
||||
};
|
||||
|
||||
test::init_service(
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state.clone()))
|
||||
.service(actix_admin_builder.get_scope::<super::AppState>())
|
||||
)
|
||||
.await
|
||||
});
|
||||
);
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub db: DatabaseConnection,
|
||||
|
Loading…
Reference in New Issue
Block a user