Enum Page to render templates with content from a struct, set html titles, with rocket responder
For each Struct to be rendered in template, put in a mod called "content" for easy importing
This commit is contained in:
parent
49a46acef3
commit
279f0bfaa3
12 changed files with 187 additions and 12 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -490,6 +490,15 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
|
|
@ -522,6 +531,7 @@ name = "ezidam"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"database_pool",
|
||||
"erased-serde",
|
||||
"infer",
|
||||
"rocket",
|
||||
"rocket_db_pools",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ rocket = "0.5.0-rc.2"
|
|||
rocket_db_pools = { version = "0.1.0-rc.2", features = ["sqlx_sqlite"] }
|
||||
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
|
||||
infer = { version = "0.12.0", default-features = false }
|
||||
erased-serde = "0.3"
|
||||
|
||||
# local crates
|
||||
database_pool = { path = "../database_pool" }
|
||||
|
|
|
|||
|
|
@ -2,8 +2,21 @@ pub(super) mod catchers;
|
|||
mod conversion;
|
||||
mod responder;
|
||||
|
||||
use crate::page::Page;
|
||||
use rocket::http::Status;
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
pub mod content {
|
||||
use rocket::serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Error {
|
||||
pub message: String,
|
||||
pub http_code: u16,
|
||||
pub http_reason: &'static str,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Error {
|
||||
status: Status,
|
||||
|
|
@ -14,16 +27,12 @@ impl Error {
|
|||
fn new<M: std::fmt::Display>(status: Status, message: M) -> Self {
|
||||
Self {
|
||||
status,
|
||||
template: Template::render(
|
||||
"error",
|
||||
context! {
|
||||
title: format!("{} Error", status.code),
|
||||
message: message.to_string(),
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
http_code: status.code,
|
||||
http_reason: status.reason_lossy()
|
||||
},
|
||||
),
|
||||
template: Page::Error(content::Error {
|
||||
message: message.to_string(),
|
||||
http_code: status.code,
|
||||
http_reason: status.reason_lossy(),
|
||||
})
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
mod database;
|
||||
mod error;
|
||||
mod file_from_bytes;
|
||||
mod page;
|
||||
mod response_timer;
|
||||
mod routes;
|
||||
mod shutdown;
|
||||
|
|
|
|||
2
crates/ezidam/src/page/content.rs
Normal file
2
crates/ezidam/src/page/content.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pub use crate::error::content::*;
|
||||
pub use crate::routes::root::content::*;
|
||||
41
crates/ezidam/src/page/mod.rs
Normal file
41
crates/ezidam/src/page/mod.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
mod content;
|
||||
mod responder;
|
||||
mod template;
|
||||
|
||||
use self::content::*;
|
||||
use erased_serde::Serialize;
|
||||
|
||||
pub enum Page {
|
||||
Error(Error),
|
||||
Setup(),
|
||||
Homepage(Homepage),
|
||||
}
|
||||
|
||||
impl Page {
|
||||
/// Template to render, the names comes from the file in "/templates"
|
||||
fn template_name(&self) -> &'static str {
|
||||
match self {
|
||||
Page::Error(_) => "error",
|
||||
Page::Setup() => "setup",
|
||||
Page::Homepage(_) => "homepage",
|
||||
}
|
||||
}
|
||||
|
||||
/// Title in the html page
|
||||
fn page_title(&self) -> &'static str {
|
||||
match self {
|
||||
Page::Error(_) => "Error",
|
||||
Page::Setup() => "Setup",
|
||||
Page::Homepage(_) => "Home",
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure to render in page
|
||||
fn content(self) -> Box<dyn Serialize> {
|
||||
match self {
|
||||
Page::Error(error) => Box::new(error),
|
||||
Page::Setup() => Box::new(()),
|
||||
Page::Homepage(homepage) => Box::new(homepage),
|
||||
}
|
||||
}
|
||||
}
|
||||
11
crates/ezidam/src/page/responder.rs
Normal file
11
crates/ezidam/src/page/responder.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use super::Page;
|
||||
use rocket::response::Responder;
|
||||
use rocket::{response, Request};
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
impl<'r, 'o: 'r> Responder<'r, 'o> for Page {
|
||||
fn respond_to(self, req: &Request) -> response::Result<'o> {
|
||||
// Render template and respond to http request
|
||||
Template::from(self).respond_to(req)
|
||||
}
|
||||
}
|
||||
26
crates/ezidam/src/page/template.rs
Normal file
26
crates/ezidam/src/page/template.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use super::Page;
|
||||
use rocket::serde::Serialize;
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
struct TemplateContent<S: Serialize> {
|
||||
title: &'static str,
|
||||
version: &'static str,
|
||||
|
||||
#[serde(flatten)]
|
||||
content: S,
|
||||
}
|
||||
|
||||
impl From<Page> for Template {
|
||||
fn from(p: Page) -> Self {
|
||||
Self::render(
|
||||
p.template_name(),
|
||||
TemplateContent {
|
||||
title: p.page_title(),
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
content: p.content(),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ pub(self) mod prelude {
|
|||
pub use crate::database::Database;
|
||||
pub use crate::error::Error;
|
||||
pub use crate::file_from_bytes::FileFromBytes;
|
||||
pub use crate::page::Page;
|
||||
pub use rocket_db_pools::Connection;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rocket::{get, routes};
|
|||
use settings::Settings;
|
||||
|
||||
pub fn routes() -> Vec<rocket::Route> {
|
||||
routes![logo]
|
||||
routes![logo, setup, homepage]
|
||||
}
|
||||
|
||||
#[get("/logo")]
|
||||
|
|
@ -14,3 +14,25 @@ async fn logo(mut db: Connection<Database>) -> Result<FileFromBytes> {
|
|||
// HTTP response
|
||||
Ok(FileFromBytes::from(settings.business_logo()))
|
||||
}
|
||||
|
||||
#[get("/setup")]
|
||||
async fn setup() -> Page {
|
||||
Page::Setup()
|
||||
}
|
||||
|
||||
pub mod content {
|
||||
use rocket::serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Homepage {
|
||||
pub abc: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/homepage")]
|
||||
async fn homepage() -> Page {
|
||||
Page::Homepage(content::Homepage {
|
||||
abc: "string".to_string(),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
5
crates/ezidam/templates/homepage.html.tera
Normal file
5
crates/ezidam/templates/homepage.html.tera
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "base" %}
|
||||
|
||||
{% block content %}
|
||||
<body>homepage goes here {{ abc }}</body>
|
||||
{% endblock content %}
|
||||
46
crates/ezidam/templates/setup.html.tera
Normal file
46
crates/ezidam/templates/setup.html.tera
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{% extends "base" %}
|
||||
|
||||
{% block content %}
|
||||
<body class=" d-flex flex-column">
|
||||
<script src="/js/demo-theme.min.js"></script>
|
||||
<div class="page page-center">
|
||||
<div class="container container-tight py-4">
|
||||
<div class="text-center mb-4">
|
||||
<a href="/" class="navbar-brand navbar-brand-autodark"><img src="http://localhost:8000/logo" height="96" alt=""></a>
|
||||
</div>
|
||||
<div class="card card-md">
|
||||
<div class="card-body text-center py-4 p-sm-5">
|
||||
<h1 class="">Welcome to Ezidam!</h1>
|
||||
<p class="text-muted">Initial setup</p>
|
||||
</div>
|
||||
<div class="hr-text hr-text-center hr-text-spaceless">first admin account</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Username</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Password</label>
|
||||
<div class="input-group input-group-flat">
|
||||
<input type="password" class="form-control" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center mt-3">
|
||||
<div class="col">
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="#" class="btn btn-primary">
|
||||
Continue
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Libs JS -->
|
||||
<!-- Tabler Core -->
|
||||
<script src="/js/tabler.min.js" defer></script>
|
||||
<script src="/js/demo.min.js" defer></script>
|
||||
</body>
|
||||
{% endblock content %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue