feat(main): Add support for Tera templates

Sets up the structure required to carry Tera templates in the
actix-web state.

The (still very barebones) index renderer has been updated to render a
Tera template.
This commit is contained in:
Vincent Ambo 2018-04-08 17:30:03 +02:00
parent b83dd99e30
commit 3db069c60d
5 changed files with 44 additions and 16 deletions

3
Cargo.lock generated
View file

@ -238,6 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -253,6 +254,8 @@ dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", "tera 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View file

@ -8,8 +8,10 @@ actix = "0.5"
actix-web = { git="https://github.com/actix/actix-web.git" } actix-web = { git="https://github.com/actix/actix-web.git" }
env_logger = "0.5" env_logger = "0.5"
diesel = { version = "1.2", features = ["postgres", "chrono", "r2d2"]} diesel = { version = "1.2", features = ["postgres", "chrono", "r2d2"]}
chrono = "0.4" chrono = { version = "0.4", features = ["serde"] }
log = "0.4" log = "0.4"
r2d2 = "*" r2d2 = "*"
futures = "*" futures = "*"
tera = "0.11" tera = "0.11"
serde = "1.0"
serde_derive = "1.0"

View file

@ -4,12 +4,19 @@ extern crate diesel;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use]
extern crate tera;
#[macro_use]
extern crate serde_derive;
extern crate chrono; extern crate chrono;
extern crate actix; extern crate actix;
extern crate actix_web; extern crate actix_web;
extern crate env_logger; extern crate env_logger;
extern crate r2d2; extern crate r2d2;
extern crate futures; extern crate futures;
extern crate serde;
pub mod schema; pub mod schema;
pub mod models; pub mod models;
@ -27,28 +34,27 @@ use models::Thread;
/// Represents the state carried by the web server actors. /// Represents the state carried by the web server actors.
struct AppState { struct AppState {
/// Address of the database actor
db: Addr<Syn, DbExecutor>, db: Addr<Syn, DbExecutor>,
/// Compiled templates
tera: tera::Tera,
} }
/// Really inefficient renderer example! /// Really inefficient renderer example!
fn render_threads(threads: Vec<Thread>) -> String { fn render_threads(tpl: &tera::Tera, threads: Vec<Thread>) -> String {
let mut res = String::new(); let mut ctx = tera::Context::new();
ctx.add("threads", &threads);
for thread in threads { tpl.render("index.html", &ctx).expect("Oh no")
res.push_str(&format!("Subject: {}\n", thread.title));
res.push_str(&format!("Posted at: {}\n\n", thread.posted));
res.push_str(&format!("{}\n", thread.body));
res.push_str("-------------------------------");
}
res
} }
fn forum_index(req: HttpRequest<AppState>) -> FutureResponse<HttpResponse> { fn forum_index(req: HttpRequest<AppState>) -> FutureResponse<HttpResponse> {
req.state().db.send(ListThreads) req.state().db.send(ListThreads)
.from_err() .from_err()
.and_then(|res| match res { .and_then(move |res| match res {
Ok(threads) => Ok(HttpResponse::from(render_threads(threads))), Ok(threads) => Ok(HttpResponse::Ok()
.content_type("text/html")
.body(render_threads(&req.state().tera, threads))),
Err(err) => { Err(err) => {
error!("Error loading threads: {}", err); error!("Error loading threads: {}", err);
Ok(HttpResponse::InternalServerError().into()) Ok(HttpResponse::InternalServerError().into())
@ -74,7 +80,10 @@ fn main() {
info!("Initialising HTTP server ..."); info!("Initialising HTTP server ...");
server::new(move || { server::new(move || {
App::with_state(AppState { db: db_addr.clone() }) let template_path = concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*");
let tera = compile_templates!(template_path);
App::with_state(AppState { db: db_addr.clone(), tera })
.middleware(middleware::Logger::default()) .middleware(middleware::Logger::default())
.route("/", http::Method::GET, &forum_index) .route("/", http::Method::GET, &forum_index)
}).bind("127.0.0.1:4567").unwrap().start(); }).bind("127.0.0.1:4567").unwrap().start();

View file

@ -1,6 +1,6 @@
use chrono::prelude::{DateTime, Utc}; use chrono::prelude::{DateTime, Utc};
#[derive(Queryable)] #[derive(Queryable, Serialize)]
pub struct Thread { pub struct Thread {
pub id: i32, pub id: i32,
pub title: String, pub title: String,

14
templates/index.html Normal file
View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<title>Converse Index page</title>
</head>
<body>
<h1>Welcome to Converse</h1>
<ul>
{% for thread in threads -%}
<li>{{ thread.title }} (posted at {{ thread.posted }})</li>
{%- endfor %}
</ul>
</body>
</html>