code: improving server setup code with more admin routes, display correct admin address

This commit is contained in:
Gabor Körber 2024-01-02 11:02:15 +01:00
parent c8aefcc0bb
commit d09bfa6da0
4 changed files with 52 additions and 19 deletions

View File

@ -6,8 +6,16 @@ pub mod domain;
pub mod state; pub mod state;
pub mod views; pub mod views;
/*
pub fn routes() -> Router<AppState> { pub fn routes() -> Router<AppState> {
Router::new().route("/", get(views::index).post(views::index_action)) Router::new()
.route("/", get(views::index).post(views::index_action))
.route("/app/:app_name", get(views::list_app))
.route(
"/app/:app_name/:model_name",
get(views::list_item_collection),
)
.route(
"/app/:app_name/:model_name/detail/:model_id",
get(views::item_details),
)
} }
*/

View File

@ -11,9 +11,6 @@ use std::sync::Arc;
pub type AdminState = Arc<AdminRegistry>; pub type AdminState = Arc<AdminRegistry>;
#[derive(Serialize)]
pub enum RepositoryData {}
pub trait AdminRepository: Send + Sync { pub trait AdminRepository: Send + Sync {
fn get_item(&self, id: usize) -> Option<Value>; fn get_item(&self, id: usize) -> Option<Value>;
fn get_list(&self) -> Value; fn get_list(&self) -> Value;
@ -61,7 +58,7 @@ impl AdminRegistry {
AdminApp { AdminApp {
name: name.to_owned(), name: name.to_owned(),
app_label: label, app_label: label,
app_url: "".to_owned(), app_url: name.to_owned().to_lowercase(),
models: vec![], models: vec![],
} }
} }

View File

@ -1,5 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use axum::extract::Path;
use axum::{extract::State, response::IntoResponse, Form}; use axum::{extract::State, response::IntoResponse, Form};
use crate::admin::domain::{AdminApp, AdminModel}; use crate::admin::domain::{AdminApp, AdminModel};
@ -150,22 +151,41 @@ pub async fn index_action(Form(example_data): Form<ExampleData>) -> impl IntoRes
"There is your answer!".to_owned() "There is your answer!".to_owned()
} }
pub async fn list_app(
templates: State<templates::Templates>,
Path(app_name): Path<String>,
) -> impl IntoResponse {
templates.render_html("admin/app_list.html", ())
}
// List Items renders the entire list item page. // List Items renders the entire list item page.
pub async fn list_item_collection(templates: State<templates::Templates>) -> impl IntoResponse { pub async fn list_item_collection(
templates: State<templates::Templates>,
Path((app_name, model_name)): Path<(String, String)>,
) -> impl IntoResponse {
templates.render_html("admin/items/list_items.html", ()) templates.render_html("admin/items/list_items.html", ())
} }
// Items Action is a POST to an item list. By default these are actions, that work on a list of items as input. // Items Action is a POST to an item list. By default these are actions, that work on a list of items as input.
pub async fn item_collection_action(Form(question): Form<Question>) -> impl IntoResponse { pub async fn item_collection_action(
Form(question): Form<Question>,
Path((app_name, model_name)): Path<(String, String)>,
) -> impl IntoResponse {
"There is your answer!".to_owned() "There is your answer!".to_owned()
} }
// Item Details shows one single dataset. // Item Details shows one single dataset.
pub async fn item_details(templates: State<templates::Templates>) -> impl IntoResponse { pub async fn item_details(
templates: State<templates::Templates>,
Path((app_name, model_name, model_id)): Path<(String, String, String)>,
) -> impl IntoResponse {
templates.render_html("admin/item_detail.html", ()) templates.render_html("admin/item_detail.html", ())
} }
// Item Action allows running an action on one single dataset. // Item Action allows running an action on one single dataset.
pub async fn item_action(Form(question): Form<Question>) -> impl IntoResponse { pub async fn item_action(
Form(question): Form<Question>,
Path((app_name, model_name, model_id)): Path<(String, String, String)>,
) -> impl IntoResponse {
"There is your answer!".to_owned() "There is your answer!".to_owned()
} }

View File

@ -11,7 +11,7 @@ use axum::{
use dotenvy::dotenv; use dotenvy::dotenv;
use log::info; use log::info;
use std::env; use std::env;
use std::net::SocketAddr; use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc; use std::sync::Arc;
async fn home(templates: State<templates::Templates>) -> impl IntoResponse { async fn home(templates: State<templates::Templates>) -> impl IntoResponse {
@ -33,7 +33,7 @@ async fn main() {
let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded."); let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded.");
let mut admin = admin::state::AdminRegistry::new("admin"); let mut admin = admin::state::AdminRegistry::new("admin");
admin.register_app("auth", "Authorities", "auth"); admin.register_app("auth", "Authorities", "auth");
let admin_router = admin.generate_router(); //let admin_router = admin.generate_router();
let state: AppState = AppState { let state: AppState = AppState {
templates: tmpl, templates: tmpl,
@ -44,7 +44,8 @@ async fn main() {
let app = Router::new() let app = Router::new()
.route("/", get(home)) .route("/", get(home))
.route("/hello", get(hello_world)) .route("/hello", get(hello_world))
.merge(admin_router) //.merge(admin_router)
.nest("/admin", admin::routes())
.nest("/howto", howto::routes()) .nest("/howto", howto::routes())
.route_service("/static/*file", handlers::static_handler.into_service()) .route_service("/static/*file", handlers::static_handler.into_service())
.fallback(handlers::not_found_handler) .fallback(handlers::not_found_handler)
@ -52,17 +53,24 @@ async fn main() {
// Run Server // Run Server
let app_host: std::net::IpAddr = env::var("APP_HOST") let app_host: std::net::IpAddr = env::var("APP_HOST")
.unwrap_or("127.0.0.1".to_string()) .unwrap_or("0.0.0.0".to_string())
.parse() .parse()
.expect("IP Address expected in APP_HOST"); .expect("IP Address expected in APP_HOST");
let app_port: u16 = env::var("APP_PORT") let app_port: u16 = env::var("APP_PORT")
.unwrap_or("3000".to_string()) .unwrap_or("3000".to_string())
.parse() .parse()
.expect("Port expected in APP_PORT"); .expect("Port expected in APP_PORT");
let addr = SocketAddr::from((app_host, app_port)); // the listen_addr is the address we bind to.
info!("listening on {}", addr); let listen_addr = SocketAddr::from((app_host, app_port));
info!("admin on: http://{}/admin", addr); // the server addr is a concrete address the user can connect to.
axum::Server::bind(&addr) let server_addr = if app_host.is_unspecified() {
SocketAddr::from(([127, 0, 0, 1], app_port))
} else {
listen_addr.clone()
};
info!("listening on {}", listen_addr);
info!("admin on: http://{}/admin", server_addr);
axum::Server::bind(&listen_addr)
.serve(app.into_make_service()) .serve(app.into_make_service())
.with_graceful_shutdown(shutdown_signal()) .with_graceful_shutdown(shutdown_signal())
.await .await