Attempt nicer url segment parsing.
This commit is contained in:
parent
3767319ff6
commit
4b5940fa48
158
src/main.rs
158
src/main.rs
@ -19,11 +19,13 @@ extern crate nickel_diesel;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
extern crate r2d2_diesel;
|
extern crate r2d2_diesel;
|
||||||
|
extern crate dotenv;
|
||||||
|
|
||||||
use nickel_diesel::{DieselMiddleware, DieselRequestExtensions};
|
use nickel_diesel::{DieselMiddleware, DieselRequestExtensions};
|
||||||
use r2d2::NopErrorHandler;
|
use r2d2::NopErrorHandler;
|
||||||
use chrono::Duration as ChDuration;
|
use chrono::Duration as ChDuration;
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
|
use dotenv::dotenv;
|
||||||
use hyper::header::{Expires, HttpDate};
|
use hyper::header::{Expires, HttpDate};
|
||||||
use nickel::{FormBody, HttpRouter, MediaType, MiddlewareResult, Nickel,
|
use nickel::{FormBody, HttpRouter, MediaType, MiddlewareResult, Nickel,
|
||||||
Request, Response, StaticFilesHandler};
|
Request, Response, StaticFilesHandler};
|
||||||
@ -50,6 +52,9 @@ use requestloggermiddleware::RequestLoggerMiddleware;
|
|||||||
mod photosdirmiddleware;
|
mod photosdirmiddleware;
|
||||||
use photosdirmiddleware::{PhotosDirMiddleware, PhotosDirRequestExtensions};
|
use photosdirmiddleware::{PhotosDirMiddleware, PhotosDirRequestExtensions};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod nickelext;
|
||||||
|
use nickelext::FromSlug;
|
||||||
|
|
||||||
macro_rules! render {
|
macro_rules! render {
|
||||||
($res:expr, $template:expr, { $($param:ident : $ptype:ty = $value:expr),* })
|
($res:expr, $template:expr, { $($param:ident : $ptype:ty = $value:expr),* })
|
||||||
@ -105,7 +110,9 @@ fn monthname(n: u8) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
dotenv().ok();
|
||||||
env_logger::init().unwrap();
|
env_logger::init().unwrap();
|
||||||
info!("Initalized logger");
|
info!("Initalized logger");
|
||||||
|
|
||||||
@ -121,22 +128,22 @@ fn main() {
|
|||||||
server.utilize(dm);
|
server.utilize(dm);
|
||||||
server.utilize(PhotosDirMiddleware::new(photos_dir()));
|
server.utilize(PhotosDirMiddleware::new(photos_dir()));
|
||||||
|
|
||||||
server.get("/login", login);
|
wrap2!(server.get /login, login);
|
||||||
server.post("/login", do_login);
|
wrap2!(server.post /login, do_login);
|
||||||
server.get("/logout", logout);
|
wrap2!(server.get /logout, logout);
|
||||||
server.get("/", all_years);
|
server.get("/", all_years);
|
||||||
server.get("/img/:id/:size", show_image);
|
wrap2!(server.get /img/:id/:size, show_image);
|
||||||
server.get("/tag/", tag_all);
|
wrap2!(server.get /tag/, tag_all);
|
||||||
server.get("/tag/:tag", tag_one);
|
wrap2!(server.get /tag/:tag, tag_one);
|
||||||
server.get("/place/", place_all);
|
wrap2!(server.get /place/, place_all);
|
||||||
server.get("/place/:slug", place_one);
|
wrap2!(server.get /place/:slug, place_one);
|
||||||
server.get("/person/", person_all);
|
wrap2!(server.get /person/, person_all);
|
||||||
server.get("/person/:slug", person_one);
|
wrap2!(server.get /person/:slug, person_one);
|
||||||
server.get("/details/:id", photo_details);
|
wrap2!(server.get /details/:id, photo_details);
|
||||||
server.get("/:year/", months_in_year);
|
wrap2!(server.get /:year/, months_in_year);
|
||||||
server.get("/:year/:month/", days_in_month);
|
wrap2!(server.get /:year/:month/, days_in_month);
|
||||||
server.get("/:year/:month/:day", all_for_day);
|
wrap2!(server.get /:year/:month/:day/, all_for_day);
|
||||||
server.get("/thisday", on_this_day);
|
wrap2!(server.get /thisday, on_this_day);
|
||||||
|
|
||||||
server.listen(&*env_or("RPHOTOS_LISTEN", "127.0.0.1:6767"));
|
server.listen(&*env_or("RPHOTOS_LISTEN", "127.0.0.1:6767"));
|
||||||
}
|
}
|
||||||
@ -181,21 +188,48 @@ fn logout<'mw>(_req: &mut Request,
|
|||||||
res.redirect("/")
|
res.redirect("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_image<'mw>(req: &mut Request,
|
enum SizeTag {
|
||||||
mut res: Response<'mw>)
|
Small,
|
||||||
|
Medium,
|
||||||
|
Large,
|
||||||
|
}
|
||||||
|
impl SizeTag {
|
||||||
|
fn px(&self) -> u32 {
|
||||||
|
match *self {
|
||||||
|
SizeTag::Small => 200,
|
||||||
|
SizeTag::Medium => 800,
|
||||||
|
SizeTag::Large => 1200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSlug for SizeTag {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
match slug {
|
||||||
|
"s" => Some(SizeTag::Small),
|
||||||
|
"m" => Some(SizeTag::Medium),
|
||||||
|
"l" => Some(SizeTag::Large),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opt<T: FromSlug>(req: &Request, name: &str) -> Option<T> {
|
||||||
|
req.param(name).and_then(T::parse_slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn show_image<'mw>(req: &Request,
|
||||||
|
mut res: Response<'mw>,
|
||||||
|
the_id: i32,
|
||||||
|
size: SizeTag)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
if let Ok(the_id) = req.param("id").unwrap().parse::<i32>() {
|
|
||||||
use rphotos::schema::photos::dsl::*;
|
use rphotos::schema::photos::dsl::*;
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
if let Ok(tphoto) = photos.find(the_id).first::<Photo>(c) {
|
if let Ok(tphoto) = photos.find(the_id).first::<Photo>(c) {
|
||||||
if req.authorized_user().is_some() || tphoto.is_public() {
|
if req.authorized_user().is_some() || tphoto.is_public() {
|
||||||
if let Some(size) = match req.param("size").unwrap() {
|
let size = size.px();
|
||||||
"s" => Some(200),
|
|
||||||
"m" => Some(800),
|
|
||||||
"l" => Some(1200),
|
|
||||||
_ => None,
|
|
||||||
} {
|
|
||||||
match req.photos().get_scaled_image(tphoto, size, size) {
|
match req.photos().get_scaled_image(tphoto, size, size) {
|
||||||
Ok(buf) => {
|
Ok(buf) => {
|
||||||
res.set(MediaType::Jpeg);
|
res.set(MediaType::Jpeg);
|
||||||
@ -210,8 +244,6 @@ fn show_image<'mw>(req: &mut Request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
res.error(StatusCode::NotFound, "No such image")
|
res.error(StatusCode::NotFound, "No such image")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,11 +259,12 @@ fn tag_all<'mw>(req: &mut Request,
|
|||||||
tags: Vec<Tag> = tags.load(c).unwrap()
|
tags: Vec<Tag> = tags.load(c).unwrap()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag_one<'mw>(req: &mut Request,
|
fn tag_one<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
tslug: String)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
use rphotos::schema::tags::dsl::*;
|
use rphotos::schema::tags::dsl::*;
|
||||||
let tslug = req.param("tag").unwrap();
|
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
if let Ok(tag) = tags.filter(slug.eq(tslug)).first::<Tag>(c) {
|
if let Ok(tag) = tags.filter(slug.eq(tslug)).first::<Tag>(c) {
|
||||||
@ -266,10 +299,10 @@ fn place_all<'mw>(req: &mut Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn place_one<'mw>(req: &mut Request,
|
fn place_one<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
tslug: String)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
use rphotos::schema::places::dsl::*;
|
use rphotos::schema::places::dsl::*;
|
||||||
let tslug = req.param("slug").unwrap();
|
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
if let Ok(place) = places.filter(slug.eq(tslug)).first::<Place>(c) {
|
if let Ok(place) = places.filter(slug.eq(tslug)).first::<Place>(c) {
|
||||||
@ -304,10 +337,10 @@ fn person_all<'mw>(req: &mut Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn person_one<'mw>(req: &mut Request,
|
fn person_one<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
tslug: String)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
use rphotos::schema::people::dsl::*;
|
use rphotos::schema::people::dsl::*;
|
||||||
let tslug = req.param("slug").unwrap();
|
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
if let Ok(person) = people.filter(slug.eq(tslug)).first::<Person>(c) {
|
if let Ok(person) = people.filter(slug.eq(tslug)).first::<Person>(c) {
|
||||||
@ -330,13 +363,13 @@ fn person_one<'mw>(req: &mut Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn photo_details<'mw>(req: &mut Request,
|
fn photo_details<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
id: i32)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
if let Ok(the_id) = req.param("id").unwrap().parse::<i32>() {
|
use rphotos::schema::photos::dsl::photos;
|
||||||
use rphotos::schema::photos::dsl::*;
|
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
if let Ok(tphoto) = photos.find(the_id).first::<Photo>(c) {
|
if let Ok(tphoto) = photos.find(id).first::<Photo>(c) {
|
||||||
if req.authorized_user().is_some() || tphoto.is_public() {
|
if req.authorized_user().is_some() || tphoto.is_public() {
|
||||||
return render!(res, "templates/details.tpl", {
|
return render!(res, "templates/details.tpl", {
|
||||||
user: Option<String> = req.authorized_user(),
|
user: Option<String> = req.authorized_user(),
|
||||||
@ -394,7 +427,6 @@ fn photo_details<'mw>(req: &mut Request,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
res.error(StatusCode::NotFound, "Photo not found")
|
res.error(StatusCode::NotFound, "Photo not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,14 +482,14 @@ fn all_years<'mw>(req: &mut Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn months_in_year<'mw>(req: &mut Request,
|
fn months_in_year<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
year: i32)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
use rphotos::schema::photos::dsl::*;
|
use rphotos::schema::photos::dsl::*;
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
|
|
||||||
if let Ok(year) = req.param("year").unwrap().parse::<i32>() {
|
render!(res, "templates/groups.tpl", {
|
||||||
return render!(res, "templates/groups.tpl", {
|
|
||||||
user: Option<String> = req.authorized_user(),
|
user: Option<String> = req.authorized_user(),
|
||||||
title: String = format!("Photos from {}", year),
|
title: String = format!("Photos from {}", year),
|
||||||
groups: Vec<Group> =
|
groups: Vec<Group> =
|
||||||
@ -496,25 +528,22 @@ fn months_in_year<'mw>(req: &mut Request,
|
|||||||
photo: photo
|
photo: photo
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
});
|
})
|
||||||
}
|
|
||||||
res.error(StatusCode::NotFound, "Not a year")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn days_in_month<'mw>(req: &mut Request,
|
fn days_in_month<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
year: i32,
|
||||||
|
month: u8)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
use rphotos::schema::photos::dsl::*;
|
use rphotos::schema::photos::dsl::*;
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
|
|
||||||
if let Ok(year) = req.param("year").unwrap().parse::<i32>() {
|
render!(res, "templates/groups.tpl", {
|
||||||
if let Ok(month) = req.param("month").unwrap().parse::<u8>() {
|
|
||||||
return render!(res, "templates/groups.tpl", {
|
|
||||||
user: Option<String> = req.authorized_user(),
|
user: Option<String> = req.authorized_user(),
|
||||||
lpath: Vec<Link> = vec![Link::year(year)],
|
lpath: Vec<Link> = vec![Link::year(year)],
|
||||||
title: String = format!("Photos from {} {}", monthname(month),
|
title: String = format!("Photos from {} {}", monthname(month), year),
|
||||||
year),
|
|
||||||
groups: Vec<Group> =
|
groups: Vec<Group> =
|
||||||
// FIXME only public if not logged on!
|
// FIXME only public if not logged on!
|
||||||
SqlLiteral::new(format!(concat!(
|
SqlLiteral::new(format!(concat!(
|
||||||
@ -530,7 +559,8 @@ fn days_in_month<'mw>(req: &mut Request,
|
|||||||
.load::<(Option<f64>, i64)>(c).unwrap()
|
.load::<(Option<f64>, i64)>(c).unwrap()
|
||||||
.iter().map(|&(day, count)| {
|
.iter().map(|&(day, count)| {
|
||||||
let day = day.map(|y| y as u32).unwrap_or(0);
|
let day = day.map(|y| y as u32).unwrap_or(0);
|
||||||
let fromdate = NaiveDate::from_ymd(year, month as u32, day).and_hms(0, 0, 0);
|
let fromdate = NaiveDate::from_ymd(year, month as u32, day)
|
||||||
|
.and_hms(0, 0, 0);
|
||||||
let photo = photos
|
let photo = photos
|
||||||
// .only_public(req.authorized_user().is_none())
|
// .only_public(req.authorized_user().is_none())
|
||||||
.filter(date.ge(fromdate))
|
.filter(date.ge(fromdate))
|
||||||
@ -547,31 +577,28 @@ fn days_in_month<'mw>(req: &mut Request,
|
|||||||
photo: photo
|
photo: photo
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
});
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
res.error(StatusCode::NotFound, "Not a month")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_for_day<'mw>(req: &mut Request,
|
fn all_for_day<'mw>(req: &mut Request,
|
||||||
res: Response<'mw>)
|
res: Response<'mw>,
|
||||||
|
year: i32,
|
||||||
|
month: u8,
|
||||||
|
day: u32)
|
||||||
-> MiddlewareResult<'mw> {
|
-> MiddlewareResult<'mw> {
|
||||||
if let Ok(year) = req.param("year").unwrap().parse::<i32>() {
|
|
||||||
if let Ok(month) = req.param("month").unwrap().parse::<u8>() {
|
|
||||||
if let Ok(day) = req.param("day").unwrap().parse::<u32>() {
|
|
||||||
let thedate = NaiveDate::from_ymd(year, month as u32, day)
|
let thedate = NaiveDate::from_ymd(year, month as u32, day)
|
||||||
.and_hms(0, 0, 0);
|
.and_hms(0, 0, 0);
|
||||||
use rphotos::schema::photos::dsl::*;
|
use rphotos::schema::photos::dsl::*;
|
||||||
let pq = photos
|
let pq = photos
|
||||||
.filter(date.ge(thedate))
|
.filter(date.ge(thedate))
|
||||||
.filter(date.lt(thedate + ChDuration::days(1)))
|
.filter(date.lt(thedate + ChDuration::days(1)))
|
||||||
//.filter(path.like("%.JPG"))
|
// .filter(path.like("%.JPG"))
|
||||||
.order((grade.desc(), date.asc()))
|
.order((grade.desc(), date.asc()))
|
||||||
.limit(500);
|
.limit(500);
|
||||||
|
|
||||||
let connection = req.db_conn();
|
let connection = req.db_conn();
|
||||||
let c: &PgConnection = &connection;
|
let c: &PgConnection = &connection;
|
||||||
return render!(res, "templates/index.tpl", {
|
render!(res, "templates/index.tpl", {
|
||||||
user: Option<String> = req.authorized_user(),
|
user: Option<String> = req.authorized_user(),
|
||||||
lpath: Vec<Link> = vec![Link::year(year),
|
lpath: Vec<Link> = vec![Link::year(year),
|
||||||
Link::month(year, month)],
|
Link::month(year, month)],
|
||||||
@ -584,11 +611,7 @@ fn all_for_day<'mw>(req: &mut Request,
|
|||||||
} else {
|
} else {
|
||||||
pq.load(c).unwrap()
|
pq.load(c).unwrap()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.error(StatusCode::NotFound, "Not a day")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_this_day<'mw>(req: &mut Request,
|
fn on_this_day<'mw>(req: &mut Request,
|
||||||
@ -602,9 +625,8 @@ fn on_this_day<'mw>(req: &mut Request,
|
|||||||
let now = time::now();
|
let now = time::now();
|
||||||
(now.tm_mon as u8 + 1, now.tm_mday as u32)
|
(now.tm_mon as u8 + 1, now.tm_mday as u32)
|
||||||
};
|
};
|
||||||
return render!(res, "templates/groups.tpl", {
|
render!(res, "templates/groups.tpl", {
|
||||||
user: Option<String> = req.authorized_user(),
|
user: Option<String> = req.authorized_user(),
|
||||||
//lpath: Vec<Link> = vec![Link::year(year)],
|
|
||||||
title: String = format!("Photos from {} {}", day, monthname(month)),
|
title: String = format!("Photos from {} {}", day, monthname(month)),
|
||||||
groups: Vec<Group> =
|
groups: Vec<Group> =
|
||||||
SqlLiteral::new(format!(concat!(
|
SqlLiteral::new(format!(concat!(
|
||||||
@ -637,7 +659,7 @@ fn on_this_day<'mw>(req: &mut Request,
|
|||||||
photo: photo
|
photo: photo
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, RustcEncodable)]
|
#[derive(Debug, Clone, RustcEncodable)]
|
||||||
|
90
src/nickelext.rs
Normal file
90
src/nickelext.rs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//! A module of stuff that might evolve into improvements in nickel
|
||||||
|
//! itself.
|
||||||
|
//! Mainly, I'm experimenting with parsing url segments.
|
||||||
|
|
||||||
|
macro_rules! wrap2 {
|
||||||
|
($server:ident.$method:ident /:$slug:ident/, $handler:ident) => {
|
||||||
|
$server.$method(
|
||||||
|
concat!("/:", stringify!($slug), "/"),
|
||||||
|
wrap!($handler: $slug)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /:$slug1:ident/:$slug2:ident/, $handler:ident) => {
|
||||||
|
$server.$method(
|
||||||
|
concat!("/:", stringify!($slug1), "/:", stringify!($slug2), "/"),
|
||||||
|
wrap!($handler: $slug1, $slug2)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /:$slug1:ident/:$slug2:ident/:$slug3:ident/, $handler:ident) => {
|
||||||
|
$server.$method(
|
||||||
|
concat!("/:", stringify!($slug1), "/:", stringify!($slug2),
|
||||||
|
"/:", stringify!($slug3)),
|
||||||
|
wrap!($handler: $slug1, $slug2, $slug3)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /$path:ident, $handler:ident ) => {
|
||||||
|
$server.$method(concat!("/", stringify!($path)), $handler)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /$path:ident/, $handler:ident ) => {
|
||||||
|
$server.$method(concat!("/", stringify!($path), "/"), $handler)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /$path:ident/:$slug:ident, $handler:ident) => {
|
||||||
|
$server.$method(
|
||||||
|
concat!("/", stringify!($path), "/:", stringify!($slug)),
|
||||||
|
wrap!($handler: $slug)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
($server:ident.$method:ident /$path:ident/:$slug:ident/:$slug2:ident, $handler:ident) => {
|
||||||
|
$server.$method(
|
||||||
|
concat!("/", stringify!($path), "/:", stringify!($slug),
|
||||||
|
"/:", stringify!($slug2)),
|
||||||
|
wrap!($handler: $slug, $slug2)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! wrap {
|
||||||
|
($handler:ident : $( $param:ident ),+ ) => { {
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
fn wrapped<'mw>(req: &mut Request,
|
||||||
|
res: Response<'mw>)
|
||||||
|
-> MiddlewareResult<'mw> {
|
||||||
|
if let ($(Some($param),)*) = ($(opt(req, stringify!($param)),)*) {
|
||||||
|
$handler(req, res, $($param),*)
|
||||||
|
} else {
|
||||||
|
res.error(StatusCode::NotFound, "Parameter mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrapped
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromSlug : Sized {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self>;
|
||||||
|
}
|
||||||
|
impl FromSlug for String {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
Some(slug.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromSlug for i32 {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
slug.parse::<Self>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromSlug for u8 {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
slug.parse::<Self>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromSlug for u16 {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
slug.parse::<Self>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromSlug for u32 {
|
||||||
|
fn parse_slug(slug: &str) -> Option<Self> {
|
||||||
|
slug.parse::<Self>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user