mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 21:12:54 +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:
|
||||
package: [
|
||||
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
|
||||
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