root_url
This commit is contained in:
parent
e8c029c9d0
commit
6816f2f9fe
|
@ -20,3 +20,4 @@ L'option `-d <dir>` permet de changer le dossier de données/config (par exemple
|
|||
|
||||
gmarche -d mon/autre/dossier/ start|init
|
||||
|
||||
Pour lancer l'instance dans un sous-dossier de l'URL (i.e. `http://example.tld/gmarche`), changez `root_url` dans la config. La valeur doit toujours commencer et terminer par un `/`.
|
||||
|
|
|
@ -12,6 +12,7 @@ pub struct Config {
|
|||
pub cookies_https_only: bool,
|
||||
pub cookies_domain: Option<String>,
|
||||
pub listen: SocketAddr,
|
||||
pub root_url: String,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -21,6 +22,7 @@ impl Default for Config {
|
|||
cookies_https_only: false,
|
||||
cookies_domain: None,
|
||||
listen: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 10353),
|
||||
root_url: String::from("/"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
100
src/server.rs
100
src/server.rs
|
@ -17,25 +17,48 @@ pub async fn start_server(
|
|||
let config = Arc::new(config);
|
||||
|
||||
let mut app = tide::new();
|
||||
app.at("/static")
|
||||
app.at(&format!("{}static", config.root_url))
|
||||
.serve_dir(opt.dir.0.join(static_files::STATIC_DIR))
|
||||
.unwrap();
|
||||
app.at("/").get({
|
||||
app.at(&config.root_url).get({
|
||||
let config = config.clone();
|
||||
let templates = templates.clone();
|
||||
let dbs = dbs.clone();
|
||||
move |req: tide::Request<()>| serve_index(req, templates.clone(), dbs.clone(), &[], None)
|
||||
move |req: tide::Request<()>| {
|
||||
serve_index(
|
||||
req,
|
||||
config.clone(),
|
||||
templates.clone(),
|
||||
dbs.clone(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
}
|
||||
});
|
||||
app.at("/").post({
|
||||
app.at(&config.root_url).post({
|
||||
let config = config.clone();
|
||||
let templates = templates.clone();
|
||||
let dbs = dbs.clone();
|
||||
move |req: tide::Request<()>| handle_post_index(req, templates.clone(), dbs.clone())
|
||||
move |req: tide::Request<()>| {
|
||||
handle_post_index(req, config.clone(), templates.clone(), dbs.clone())
|
||||
}
|
||||
});
|
||||
app.at("/ad/:ad").get({
|
||||
app.at(&format!("{}ad/:ad", config.root_url)).get({
|
||||
let config = config.clone();
|
||||
let templates = templates.clone();
|
||||
let dbs = dbs.clone();
|
||||
move |req: tide::Request<()>| serve_index(req, templates.clone(), dbs.clone(), &[], None)
|
||||
move |req: tide::Request<()>| {
|
||||
serve_index(
|
||||
req,
|
||||
config.clone(),
|
||||
templates.clone(),
|
||||
dbs.clone(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
}
|
||||
});
|
||||
app.at("/admin").get({
|
||||
app.at(&format!("{}admin", config.root_url)).get({
|
||||
let config = config.clone();
|
||||
let templates = templates.clone();
|
||||
let dbs = dbs.clone();
|
||||
|
@ -43,18 +66,22 @@ pub async fn start_server(
|
|||
handle_admin(req, config.clone(), templates.clone(), dbs.clone())
|
||||
}
|
||||
});
|
||||
app.at("/admin").post({
|
||||
app.at(&format!("{}admin", config.root_url)).post({
|
||||
let config = config.clone();
|
||||
move |req: tide::Request<()>| {
|
||||
handle_post_admin(req, config.clone(), templates.clone(), dbs.clone())
|
||||
}
|
||||
});
|
||||
app.at("/admin/logout").get(handle_admin_logout);
|
||||
app.at(&format!("{}admin/logout", config.root_url)).get({
|
||||
let config = config.clone();
|
||||
move |req: tide::Request<()>| handle_admin_logout(req, config.clone())
|
||||
});
|
||||
app.listen(config.listen).await.unwrap();
|
||||
}
|
||||
|
||||
async fn serve_index<'a>(
|
||||
req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
dbs: db::Dbs,
|
||||
errors: &[ErrorTemplate<'a>],
|
||||
|
@ -70,6 +97,7 @@ async fn serve_index<'a>(
|
|||
"index.html",
|
||||
&IndexTemplate {
|
||||
lang: "fr",
|
||||
root_url: &config.root_url,
|
||||
errors,
|
||||
ads: &to_json(
|
||||
dbs.ads
|
||||
|
@ -95,6 +123,7 @@ async fn serve_index<'a>(
|
|||
|
||||
async fn serve_admin<'a>(
|
||||
req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
dbs: db::Dbs,
|
||||
errors: &[ErrorTemplate<'a>],
|
||||
|
@ -109,6 +138,7 @@ async fn serve_admin<'a>(
|
|||
"admin.html",
|
||||
&AdminTemplate {
|
||||
lang: "fr",
|
||||
root_url: &config.root_url,
|
||||
errors,
|
||||
ads: &to_json(
|
||||
dbs.ads
|
||||
|
@ -133,6 +163,7 @@ async fn serve_admin<'a>(
|
|||
|
||||
async fn serve_admin_login<'a>(
|
||||
_req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
errors: &[ErrorTemplate<'a>],
|
||||
) -> tide::Result<tide::Response> {
|
||||
|
@ -143,7 +174,11 @@ async fn serve_admin_login<'a>(
|
|||
.hb
|
||||
.render(
|
||||
"admin_login.html",
|
||||
&AdminLoginTemplate { lang: "fr", errors },
|
||||
&AdminLoginTemplate {
|
||||
lang: "fr",
|
||||
root_url: &config.root_url,
|
||||
errors,
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|e| e.to_string()),
|
||||
)
|
||||
|
@ -152,17 +187,23 @@ async fn serve_admin_login<'a>(
|
|||
|
||||
async fn handle_post_index(
|
||||
mut req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
dbs: db::Dbs,
|
||||
) -> tide::Result<tide::Response> {
|
||||
match req.body_form::<Query>().await? {
|
||||
Query::NewAdQuery(query) => handle_new_ad(req, templates.clone(), dbs.clone(), query).await,
|
||||
Query::RmAdQuery(query) => handle_rm_ad(req, templates.clone(), dbs.clone(), query).await,
|
||||
Query::NewAdQuery(query) => {
|
||||
handle_new_ad(req, config.clone(), templates.clone(), dbs.clone(), query).await
|
||||
}
|
||||
Query::RmAdQuery(query) => {
|
||||
handle_rm_ad(req, config.clone(), templates.clone(), dbs.clone(), query).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_new_ad(
|
||||
req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
dbs: db::Dbs,
|
||||
query: NewAdQuery,
|
||||
|
@ -180,6 +221,7 @@ async fn handle_new_ad(
|
|||
Ok(pubkey) => pubkey,
|
||||
Err(e) => return serve_index(
|
||||
req,
|
||||
config,
|
||||
templates,
|
||||
dbs,
|
||||
&[ErrorTemplate {
|
||||
|
@ -208,11 +250,12 @@ async fn handle_new_ad(
|
|||
)
|
||||
.unwrap();
|
||||
dbs.ads.flush().unwrap();
|
||||
Ok(tide::Redirect::new("/").into())
|
||||
Ok(tide::Redirect::new(&config.root_url).into())
|
||||
}
|
||||
|
||||
async fn handle_rm_ad(
|
||||
req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
templates: Arc<Templates<'static>>,
|
||||
dbs: db::Dbs,
|
||||
query: RmAdQuery,
|
||||
|
@ -244,6 +287,7 @@ async fn handle_rm_ad(
|
|||
} else {
|
||||
return serve_index(
|
||||
req,
|
||||
config,
|
||||
templates,
|
||||
dbs,
|
||||
&[ErrorTemplate {
|
||||
|
@ -257,7 +301,7 @@ async fn handle_rm_ad(
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(tide::Redirect::new("/").into())
|
||||
Ok(tide::Redirect::new(&config.root_url).into())
|
||||
}
|
||||
|
||||
async fn handle_admin(
|
||||
|
@ -268,10 +312,11 @@ async fn handle_admin(
|
|||
) -> tide::Result<tide::Response> {
|
||||
if let Some(psw) = req.cookie("admin") {
|
||||
if config.admin_passwords.contains(&String::from(psw.value())) {
|
||||
serve_admin(req, templates, dbs, &[]).await
|
||||
serve_admin(req, config, templates, dbs, &[]).await
|
||||
} else {
|
||||
serve_admin_login(
|
||||
req,
|
||||
config,
|
||||
templates,
|
||||
&[ErrorTemplate {
|
||||
text: "Mot de passe administrateur invalide",
|
||||
|
@ -280,7 +325,7 @@ async fn handle_admin(
|
|||
.await
|
||||
}
|
||||
} else {
|
||||
serve_admin_login(req, templates, &[]).await
|
||||
serve_admin_login(req, config, templates, &[]).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,13 +346,14 @@ async fn handle_post_admin(
|
|||
dbs.ads.flush().unwrap();
|
||||
}
|
||||
}
|
||||
Ok(tide::Redirect::new("/admin").into())
|
||||
Ok(tide::Redirect::new(&format!("{}admin", config.root_url)).into())
|
||||
}
|
||||
_ => serve_admin(req, templates, dbs, &[]).await,
|
||||
_ => serve_admin(req, config, templates, dbs, &[]).await,
|
||||
}
|
||||
} else {
|
||||
serve_admin_login(
|
||||
req,
|
||||
config,
|
||||
templates,
|
||||
&[ErrorTemplate {
|
||||
text: "Mot de passe administrateur invalide",
|
||||
|
@ -317,16 +363,19 @@ async fn handle_post_admin(
|
|||
}
|
||||
} else if let AdminQuery::LoginQuery(query) = req.body_form::<AdminQuery>().await? {
|
||||
if config.admin_passwords.contains(&query.psw) {
|
||||
serve_admin(req, templates, dbs, &[]).await.map(|mut r| {
|
||||
serve_admin(req, config.clone(), templates, dbs, &[])
|
||||
.await
|
||||
.map(|mut r| {
|
||||
let mut cookie = tide::http::Cookie::new("admin", query.psw);
|
||||
cookie.set_http_only(Some(true));
|
||||
cookie.set_path("/");
|
||||
cookie.set_path(config.root_url.clone());
|
||||
r.insert_cookie(cookie);
|
||||
r
|
||||
})
|
||||
} else {
|
||||
serve_admin_login(
|
||||
req,
|
||||
config,
|
||||
templates,
|
||||
&[ErrorTemplate {
|
||||
text: "Mot de passe administrateur invalide",
|
||||
|
@ -335,14 +384,17 @@ async fn handle_post_admin(
|
|||
.await
|
||||
}
|
||||
} else {
|
||||
serve_admin_login(req, templates, &[]).await
|
||||
serve_admin_login(req, config, templates, &[]).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_admin_logout(req: tide::Request<()>) -> tide::Result<tide::Response> {
|
||||
async fn handle_admin_logout(
|
||||
req: tide::Request<()>,
|
||||
config: Arc<config::Config>,
|
||||
) -> tide::Result<tide::Response> {
|
||||
let mut r: tide::Response = tide::Redirect::new("/").into();
|
||||
if let Some(mut cookie) = req.cookie("admin") {
|
||||
cookie.set_path("/");
|
||||
cookie.set_path(config.root_url.clone());
|
||||
r.remove_cookie(cookie);
|
||||
}
|
||||
Ok(r)
|
||||
|
|
|
@ -49,6 +49,7 @@ pub fn load_templates<'reg>(dir: &Path) -> Templates<'reg> {
|
|||
#[derive(Serialize)]
|
||||
pub struct IndexTemplate<'a> {
|
||||
pub lang: &'a str,
|
||||
pub root_url: &'a str,
|
||||
pub errors: &'a [ErrorTemplate<'a>],
|
||||
pub ads: &'a Json,
|
||||
pub new_ad_form_refill: Option<NewAdQuery>,
|
||||
|
@ -57,12 +58,14 @@ pub struct IndexTemplate<'a> {
|
|||
#[derive(Serialize)]
|
||||
pub struct AdminLoginTemplate<'a> {
|
||||
pub lang: &'a str,
|
||||
pub root_url: &'a str,
|
||||
pub errors: &'a [ErrorTemplate<'a>],
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct AdminTemplate<'a> {
|
||||
pub lang: &'a str,
|
||||
pub root_url: &'a str,
|
||||
pub errors: &'a [ErrorTemplate<'a>],
|
||||
pub ads: &'a Json,
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Administration | ĞMarché</title>
|
||||
<link rel="stylesheet" href="/static/style1.css"/>
|
||||
<link rel="shortcut icon" href="/static/icon.png"/>
|
||||
<script type="text/javascript" src="/static/script1.js"></script>
|
||||
<link rel="stylesheet" href="{{root_url}}static/style1.css"/>
|
||||
<link rel="shortcut icon" href="{{root_url}}static/icon.png"/>
|
||||
<script type="text/javascript" src="{{root_url}}static/script1.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="center page">
|
||||
<header>
|
||||
<a href="/"><img id="banner" alt="Bannière ĞMarché" src="/static/banner.jpg"/></a>
|
||||
<a href="{{root_url}}"><img id="banner" alt="Bannière ĞMarché" src="{{root_url}}static/banner.jpg"/></a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
@ -38,7 +38,7 @@
|
|||
{{#each ads}}
|
||||
<tr>
|
||||
<td><input type="radio" name="ad" value="{{this.id}}" aria-label="Sélectionner l'annonce" required/></td>
|
||||
<td onclick="ad_detail(event,'{{this.id}}')" title="Afficher le détail"><a href="/admin/ad/{{this.id}}">{{this.ad.title}}</a></td>
|
||||
<td onclick="ad_detail(event,'{{this.id}}')" title="Afficher le détail"><a href="{{root_url}}admin/ad/{{this.id}}">{{this.ad.title}}</a></td>
|
||||
<td>{{this.ad.quantity}}</td>
|
||||
<td>{{this.ad.author}}</td>
|
||||
</tr>
|
||||
|
@ -73,7 +73,7 @@
|
|||
CopyLeft 2020 Pascal Engélibert<br/>
|
||||
Image de fond : Claudia Peters, FreeImages.com</p>
|
||||
|
||||
<p><a href="/">Accueil</a> – <a href="/admin/logout">Verrouiller</a></p>
|
||||
<p><a href="{{root_url}}">Accueil</a> – <a href="{{root_url}}admin/logout">Verrouiller</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Administration | ĞMarché</title>
|
||||
<link rel="stylesheet" href="/static/style1.css"/>
|
||||
<link rel="shortcut icon" href="/static/icon.png"/>
|
||||
<link rel="stylesheet" href="{{root_url}}static/style1.css"/>
|
||||
<link rel="shortcut icon" href="{{root_url}}static/icon.png"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="center page">
|
||||
<header>
|
||||
<a href="/"><img id="banner" alt="Bannière ĞMarché" src="/static/banner.jpg"/></a>
|
||||
<a href="{{root_url}}"><img id="banner" alt="Bannière ĞMarché" src="{{root_url}}static/banner.jpg"/></a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
@ -28,7 +28,7 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
<form action="/admin" method="post">
|
||||
<form method="post">
|
||||
<input type="hidden" name="a" value="login" autocomplete="off"/>
|
||||
<label for="f_psw">Mot de passe :</label>
|
||||
<input type="password" id="f_psw" name="psw" autofocus/>
|
||||
|
@ -45,7 +45,7 @@
|
|||
CopyLeft 2020 Pascal Engélibert<br/>
|
||||
Image de fond : Claudia Peters, FreeImages.com</p>
|
||||
|
||||
<p><a href="/">Accueil</a></p>
|
||||
<p><a href="{{root_url}}">Accueil</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>ĞMarché</title>
|
||||
<link rel="stylesheet" href="/static/style1.css"/>
|
||||
<link rel="shortcut icon" href="/static/icon.png"/>
|
||||
<script type="text/javascript" src="/static/script1.js"></script>
|
||||
<link rel="stylesheet" href="{{root_url}}static/style1.css"/>
|
||||
<link rel="shortcut icon" href="{{root_url}}static/icon.png"/>
|
||||
<script type="text/javascript" src="{{root_url}}static/script1.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="center page">
|
||||
<header>
|
||||
<a href="/"><img id="banner" alt="Bannière ĞMarché" src="/static/banner.jpg"/></a>
|
||||
<a href="{{root_url}}"><img id="banner" alt="Bannière ĞMarché" src="{{root_url}}static/banner.jpg"/></a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
@ -42,7 +42,7 @@
|
|||
{{#each ads}}
|
||||
<tr>
|
||||
<td><input type="radio" name="ad" value="{{this.id}}" aria-label="Sélectionner l'annonce" required/></td>
|
||||
<td onclick="ad_detail(event,'{{this.id}}')" title="Afficher le détail"><a href="/ad/{{this.id}}">{{this.ad.title}}</a></td>
|
||||
<td onclick="ad_detail(event,'{{this.id}}')" title="Afficher le détail"><a href="{{root_url}}ad/{{this.id}}">{{this.ad.title}}</a></td>
|
||||
<td>{{this.ad.quantity}}</td>
|
||||
<td>{{this.ad.author}}</td>
|
||||
</tr>
|
||||
|
@ -69,7 +69,7 @@
|
|||
<p>Il n'y a pas encore d'annonce ici.</p>
|
||||
{{/if}}
|
||||
|
||||
<img id="stand" alt="Marché" src="/static/standgm.png"/>
|
||||
<img id="stand" alt="Marché" src="{{root_url}}static/standgm.png"/>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="a" value="new_ad" autocomplete="off"/>
|
||||
|
@ -102,7 +102,7 @@
|
|||
CopyLeft 2020 Pascal Engélibert<br/>
|
||||
Image de fond : Claudia Peters, FreeImages.com</p>
|
||||
|
||||
<p><a href="/admin">Administration</a></p>
|
||||
<p><a href="{{root_url}}admin">Administration</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue