mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
Add example app
This commit is contained in:
parent
e3c1fe3548
commit
efcffeea78
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
package: [
|
package: [
|
||||||
rinja, rinja_actix, rinja_axum, rinja_derive, rinja_derive_standalone, rinja_escape,
|
rinja, rinja_actix, rinja_axum, rinja_derive, rinja_derive_standalone, rinja_escape,
|
||||||
rinja_parser, rinja_rocket, rinja_warp, testing,
|
rinja_parser, rinja_rocket, rinja_warp, testing, examples/actix-web-app,
|
||||||
]
|
]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
20
examples/actix-web-app/Cargo.toml
Normal file
20
examples/actix-web-app/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "actix-web-app"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rinja_actix = { version = "0.15.0", path = "../../rinja_actix" }
|
||||||
|
|
||||||
|
actix-web = { version = "4.8.0", default-features = false, features = ["macros"] }
|
||||||
|
env_logger = "0.11.3"
|
||||||
|
log = "0.4.22"
|
||||||
|
pretty-error-debug = "0.3.0"
|
||||||
|
serde = { version = "1.0.203", features = ["derive"] }
|
||||||
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
|
thiserror = "1.0.61"
|
||||||
|
tokio = { version = "1.38.0", features = ["sync", "rt-multi-thread"] }
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["."]
|
1
examples/actix-web-app/LICENSE-APACHE
Symbolic link
1
examples/actix-web-app/LICENSE-APACHE
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../LICENSE-APACHE
|
1
examples/actix-web-app/LICENSE-MIT
Symbolic link
1
examples/actix-web-app/LICENSE-MIT
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../LICENSE-MIT
|
137
examples/actix-web-app/src/main.rs
Normal file
137
examples/actix-web-app/src/main.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use actix_web::http::{header, Method};
|
||||||
|
use actix_web::{
|
||||||
|
get, middleware, web, App, Either, HttpRequest, HttpResponse, HttpServer, Responder, Result,
|
||||||
|
};
|
||||||
|
use rinja_actix::Template;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tokio::runtime;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let env = env_logger::Env::new().default_filter_or("info");
|
||||||
|
env_logger::try_init_from_env(env).map_err(Error::Log)?;
|
||||||
|
|
||||||
|
runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.map_err(Error::Rt)?
|
||||||
|
.block_on(amain())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn amain() -> Result<(), Error> {
|
||||||
|
let server = HttpServer::new(|| {
|
||||||
|
App::new()
|
||||||
|
.wrap(middleware::Logger::default())
|
||||||
|
.wrap(middleware::NormalizePath::new(
|
||||||
|
middleware::TrailingSlash::MergeOnly,
|
||||||
|
))
|
||||||
|
.service(start_handler)
|
||||||
|
.service(index_handler)
|
||||||
|
.service(greeting_handler)
|
||||||
|
.default_service(web::to(not_found_handler))
|
||||||
|
});
|
||||||
|
let server = server.bind(("127.0.0.1", 8080)).map_err(Error::Bind)?;
|
||||||
|
for addr in server.addrs() {
|
||||||
|
println!("Listening on: http://{addr}/");
|
||||||
|
}
|
||||||
|
server.run().await.map_err(Error::Run)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, pretty_error_debug::Debug)]
|
||||||
|
enum Error {
|
||||||
|
#[error("could not setup logger")]
|
||||||
|
Log(#[source] log::SetLoggerError),
|
||||||
|
#[error("could not setup async runtime")]
|
||||||
|
Rt(#[source] std::io::Error),
|
||||||
|
#[error("could not bind socket")]
|
||||||
|
Bind(#[source] std::io::Error),
|
||||||
|
#[error("could not run server")]
|
||||||
|
Run(#[source] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Deserialize, strum::Display, strum::AsRefStr)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
enum Lang {
|
||||||
|
#[default]
|
||||||
|
en,
|
||||||
|
de,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn not_found_handler(req: HttpRequest) -> Result<impl Responder> {
|
||||||
|
#[derive(Debug, Template)]
|
||||||
|
#[template(path = "404.html")]
|
||||||
|
struct Tmpl {
|
||||||
|
req: HttpRequest,
|
||||||
|
lang: Lang,
|
||||||
|
}
|
||||||
|
|
||||||
|
match req.method() {
|
||||||
|
&Method::GET => Ok(Either::Left(Tmpl {
|
||||||
|
req,
|
||||||
|
lang: Lang::default(),
|
||||||
|
})),
|
||||||
|
_ => Ok(Either::Right(HttpResponse::MethodNotAllowed().finish())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn start_handler(req: HttpRequest) -> Result<impl Responder> {
|
||||||
|
let url = req.url_for("index_handler", [Lang::default()])?;
|
||||||
|
Ok(HttpResponse::Found()
|
||||||
|
.insert_header((header::LOCATION, url.as_str()))
|
||||||
|
.finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct IndexHandlerQuery {
|
||||||
|
#[serde(default)]
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/{lang}/index.html")]
|
||||||
|
async fn index_handler(
|
||||||
|
req: HttpRequest,
|
||||||
|
path: web::Path<(Lang,)>,
|
||||||
|
web::Query(query): web::Query<IndexHandlerQuery>,
|
||||||
|
) -> Result<impl Responder> {
|
||||||
|
#[derive(Debug, Template)]
|
||||||
|
#[template(path = "index.html")]
|
||||||
|
struct Tmpl {
|
||||||
|
req: HttpRequest,
|
||||||
|
lang: Lang,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (lang,) = path.into_inner();
|
||||||
|
Ok(Tmpl {
|
||||||
|
req,
|
||||||
|
lang,
|
||||||
|
name: query.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct GreetingHandlerQuery {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/{lang}/greet-me.html")]
|
||||||
|
async fn greeting_handler(
|
||||||
|
req: HttpRequest,
|
||||||
|
path: web::Path<(Lang,)>,
|
||||||
|
web::Query(query): web::Query<GreetingHandlerQuery>,
|
||||||
|
) -> Result<impl Responder> {
|
||||||
|
#[derive(Debug, Template)]
|
||||||
|
#[template(path = "greet.html")]
|
||||||
|
struct Tmpl {
|
||||||
|
req: HttpRequest,
|
||||||
|
lang: Lang,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (lang,) = path.into_inner();
|
||||||
|
Ok(Tmpl {
|
||||||
|
req,
|
||||||
|
lang,
|
||||||
|
name: query.name,
|
||||||
|
})
|
||||||
|
}
|
10
examples/actix-web-app/templates/404.html
Normal file
10
examples/actix-web-app/templates/404.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% extends "_layout.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
404: Not Found
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block content -%}
|
||||||
|
<h1>404: Not Found</h1>
|
||||||
|
<h2><a href="{{ req.url_for_static("start_handler")? }}">Back to the first page.</a></h2>
|
||||||
|
{%- endblock %}
|
53
examples/actix-web-app/templates/_layout.html
Normal file
53
examples/actix-web-app/templates/_layout.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{lang}}">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
<meta http-equiv="expires" content="Sat, 01 Dec 2001 00:00:00 GMT" />
|
||||||
|
<meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate" />
|
||||||
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="robots" content="noindex, nofollow" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/*<![CDATA[*/
|
||||||
|
html {
|
||||||
|
background-color: #eee;
|
||||||
|
color: #111;
|
||||||
|
font-size: 62.5%;
|
||||||
|
min-height: 100vh;
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
max-width: 40em;
|
||||||
|
margin: 1em auto;
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
h1 { font-size: 2.4rem; }
|
||||||
|
h2 { font-size: 2.2rem; }
|
||||||
|
h3 { font-size: 2.0rem; }
|
||||||
|
a:link, a:visited {
|
||||||
|
color: #36c;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:active, a:hover, a:focus {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 0.3em;
|
||||||
|
}
|
||||||
|
#lang-select {
|
||||||
|
font-size: 80%;
|
||||||
|
width: max-content;
|
||||||
|
margin: 2em 0 0 auto;
|
||||||
|
}
|
||||||
|
/*]]>*/
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{%~ block content %}{% endblock ~%}
|
||||||
|
</body>
|
||||||
|
</html>
|
44
examples/actix-web-app/templates/greet.html
Normal file
44
examples/actix-web-app/templates/greet.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{% extends "_layout.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Hello, {{name}}!
|
||||||
|
{%- when Lang::de -%} Hallo, {{name}}!
|
||||||
|
{%- endmatch -%}
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{%- block content -%}
|
||||||
|
<h1>
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Hello
|
||||||
|
{%- when Lang::de -%} Hallo
|
||||||
|
{%- endmatch -%}
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%}
|
||||||
|
Hello, <strong>{{name}}</strong>, nice to meet you! {#-~#}
|
||||||
|
I'm a <a href="https://rinja.readthedocs.io/en/latest/">Rinja</a> example application.
|
||||||
|
{%- when Lang::de -%}
|
||||||
|
Hallo, <strong>{{name}}</strong>, schön dich kennenzulernen! {#-~#}
|
||||||
|
Ich bin eine <a href="https://rinja.readthedocs.io/en/latest/">Rinja</a>-Beispielanwendung.
|
||||||
|
{%- endmatch -%}
|
||||||
|
</p>
|
||||||
|
<h2>
|
||||||
|
<a href="{{ req.url_for("index_handler", [lang])? }}?name={{ name|urlencode }}">
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Back to the first page.
|
||||||
|
{%- when Lang::de -%} Zurück zur ersten Seite.
|
||||||
|
{%- endmatch -%}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul id="lang-select">
|
||||||
|
{%- if lang != Lang::en -%}
|
||||||
|
<li><a href="{{ req.url_for("greeting_handler", [Lang::en])? }}?name={{ name|urlencode }}">This page in English</a></li>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if lang != Lang::de -%}
|
||||||
|
<li><a href="{{ req.url_for("greeting_handler", [Lang::de])? }}?name={{ name|urlencode }}">Diese Seite auf deutsch.</a></li>
|
||||||
|
{%- endif -%}
|
||||||
|
</ul>
|
||||||
|
{%- endblock %}
|
67
examples/actix-web-app/templates/index.html
Normal file
67
examples/actix-web-app/templates/index.html
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{% extends "_layout.html" %}
|
||||||
|
|
||||||
|
{% block title -%}
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Hello
|
||||||
|
{%- when Lang::de -%} Hallo
|
||||||
|
{%- endmatch -%}
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{%- block content -%}
|
||||||
|
<h1>
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Hello
|
||||||
|
{%- when Lang::de -%} Hallo
|
||||||
|
{%- endmatch -%}
|
||||||
|
</h1>
|
||||||
|
<form
|
||||||
|
method="GET"
|
||||||
|
action="{{ req.url_for("greeting_handler", [lang])? }}"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%}
|
||||||
|
I would like to say <em>hello</em>. {#-~#}
|
||||||
|
Would you please tell me your name?
|
||||||
|
{%- when Lang::de -%}
|
||||||
|
Ich möchte dir gerne <em>hallo</em> sagen. {#-~#}
|
||||||
|
Bitte nenne mir doch deinen Namen!
|
||||||
|
{%- endmatch -%}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} My name is
|
||||||
|
{%- when Lang::de -%} Ich heiße
|
||||||
|
{%- endmatch -%}:
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="{{name}}"
|
||||||
|
name="name"
|
||||||
|
required
|
||||||
|
style="width: 10em"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<button type="submit">
|
||||||
|
{%- match lang -%}
|
||||||
|
{%- when Lang::en -%} Greet me, then!
|
||||||
|
{%- when Lang::de -%} Dann begrüße mich!
|
||||||
|
{%- endmatch -%}
|
||||||
|
</button>
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<ul id="lang-select">
|
||||||
|
{%- if lang != Lang::en -%}
|
||||||
|
<li><a href="{{ req.url_for("index_handler", [Lang::en])? }}">This page in English</a></li>
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if lang != Lang::de -%}
|
||||||
|
<li><a href="{{ req.url_for("index_handler", [Lang::de])? }}">Diese Seite auf deutsch.</a></li>
|
||||||
|
{%- endif -%}
|
||||||
|
</ul>
|
||||||
|
{%- endblock %}
|
Loading…
x
Reference in New Issue
Block a user