diff --git a/src/admin/mod.rs b/src/admin/mod.rs index 53018d6..5751bac 100644 --- a/src/admin/mod.rs +++ b/src/admin/mod.rs @@ -6,8 +6,16 @@ pub mod domain; pub mod state; pub mod views; -/* pub fn routes() -> Router { - 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), + ) } - */ diff --git a/src/admin/state.rs b/src/admin/state.rs index 8e26e90..2a65d8c 100644 --- a/src/admin/state.rs +++ b/src/admin/state.rs @@ -11,9 +11,6 @@ use std::sync::Arc; pub type AdminState = Arc; -#[derive(Serialize)] -pub enum RepositoryData {} - pub trait AdminRepository: Send + Sync { fn get_item(&self, id: usize) -> Option; fn get_list(&self) -> Value; @@ -61,7 +58,7 @@ impl AdminRegistry { AdminApp { name: name.to_owned(), app_label: label, - app_url: "".to_owned(), + app_url: name.to_owned().to_lowercase(), models: vec![], } } diff --git a/src/admin/views.rs b/src/admin/views.rs index 479a787..d5396d8 100644 --- a/src/admin/views.rs +++ b/src/admin/views.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use axum::extract::Path; use axum::{extract::State, response::IntoResponse, Form}; use crate::admin::domain::{AdminApp, AdminModel}; @@ -150,22 +151,41 @@ pub async fn index_action(Form(example_data): Form) -> impl IntoRes "There is your answer!".to_owned() } +pub async fn list_app( + templates: State, + Path(app_name): Path, +) -> impl IntoResponse { + templates.render_html("admin/app_list.html", ()) +} + // List Items renders the entire list item page. -pub async fn list_item_collection(templates: State) -> impl IntoResponse { +pub async fn list_item_collection( + templates: State, + Path((app_name, model_name)): Path<(String, String)>, +) -> impl IntoResponse { 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. -pub async fn item_collection_action(Form(question): Form) -> impl IntoResponse { +pub async fn item_collection_action( + Form(question): Form, + Path((app_name, model_name)): Path<(String, String)>, +) -> impl IntoResponse { "There is your answer!".to_owned() } // Item Details shows one single dataset. -pub async fn item_details(templates: State) -> impl IntoResponse { +pub async fn item_details( + templates: State, + Path((app_name, model_name, model_id)): Path<(String, String, String)>, +) -> impl IntoResponse { templates.render_html("admin/item_detail.html", ()) } // Item Action allows running an action on one single dataset. -pub async fn item_action(Form(question): Form) -> impl IntoResponse { +pub async fn item_action( + Form(question): Form, + Path((app_name, model_name, model_id)): Path<(String, String, String)>, +) -> impl IntoResponse { "There is your answer!".to_owned() } diff --git a/src/main.rs b/src/main.rs index 3723ac3..317f6f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use axum::{ use dotenvy::dotenv; use log::info; use std::env; -use std::net::SocketAddr; +use std::net::{Ipv4Addr, SocketAddr}; use std::sync::Arc; async fn home(templates: State) -> impl IntoResponse { @@ -33,7 +33,7 @@ async fn main() { let tmpl = templates::Templates::initialize().expect("Template Engine could not be loaded."); let mut admin = admin::state::AdminRegistry::new("admin"); admin.register_app("auth", "Authorities", "auth"); - let admin_router = admin.generate_router(); + //let admin_router = admin.generate_router(); let state: AppState = AppState { templates: tmpl, @@ -44,7 +44,8 @@ async fn main() { let app = Router::new() .route("/", get(home)) .route("/hello", get(hello_world)) - .merge(admin_router) + //.merge(admin_router) + .nest("/admin", admin::routes()) .nest("/howto", howto::routes()) .route_service("/static/*file", handlers::static_handler.into_service()) .fallback(handlers::not_found_handler) @@ -52,17 +53,24 @@ async fn main() { // Run Server 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() .expect("IP Address expected in APP_HOST"); let app_port: u16 = env::var("APP_PORT") .unwrap_or("3000".to_string()) .parse() .expect("Port expected in APP_PORT"); - let addr = SocketAddr::from((app_host, app_port)); - info!("listening on {}", addr); - info!("admin on: http://{}/admin", addr); - axum::Server::bind(&addr) + // the listen_addr is the address we bind to. + let listen_addr = SocketAddr::from((app_host, app_port)); + // the server addr is a concrete address the user can connect to. + 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()) .with_graceful_shutdown(shutdown_signal()) .await