Redirect after-pagination queries to the corresponding before-queries
This normalizes the URLs, avoiding duplicate URLs for a sublist
This commit is contained in:
parent
7a63fdca0e
commit
b3ffcb916b
4 changed files with 58 additions and 7 deletions
|
@ -11,16 +11,19 @@ use state::State;
|
||||||
use web::{Resource, ResponseFuture};
|
use web::{Resource, ResponseFuture};
|
||||||
|
|
||||||
use super::pagination::Pagination;
|
use super::pagination::Pagination;
|
||||||
|
use super::TemporaryRedirectResource;
|
||||||
|
|
||||||
const PAGE_SIZE: i32 = 30;
|
const PAGE_SIZE: i32 = 30;
|
||||||
|
|
||||||
|
type BoxResource = Box<Resource + Sync + Send>;
|
||||||
|
|
||||||
pub struct ChangesResource {
|
pub struct ChangesResource {
|
||||||
state: State,
|
state: State,
|
||||||
before: Option<i32>,
|
before: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChangesResource {
|
impl ChangesResource {
|
||||||
pub fn new(state: State, pagination: Pagination<i32>) -> Box<Future<Item=ChangesResource, Error=::web::Error>> {
|
pub fn new(state: State, pagination: Pagination<i32>) -> Box<Future<Item=BoxResource, Error=::web::Error>> {
|
||||||
match pagination {
|
match pagination {
|
||||||
Pagination::After(x) => Box::new(
|
Pagination::After(x) => Box::new(
|
||||||
state.query_article_revision_stubs(move |query| {
|
state.query_article_revision_stubs(move |query| {
|
||||||
|
@ -38,14 +41,14 @@ impl ChangesResource {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(match extra_element {
|
||||||
state,
|
Some(x) => Box::new(TemporaryRedirectResource::new(format!("?before={}", x.sequence_number))) as BoxResource,
|
||||||
before: extra_element.map(|x| x.sequence_number),
|
None => Box::new(TemporaryRedirectResource::new(format!("_changes"))) as BoxResource,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
Pagination::Before(x) => Box::new(finished(Self { state, before: Some(x) })),
|
Pagination::Before(x) => Box::new(finished(Box::new(Self { state, before: Some(x) }) as BoxResource)),
|
||||||
Pagination::None => Box::new(finished(Self { state, before: None })),
|
Pagination::None => Box::new(finished(Box::new(Self { state, before: None }) as BoxResource)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@ mod article_resource;
|
||||||
mod changes_resource;
|
mod changes_resource;
|
||||||
mod new_article_resource;
|
mod new_article_resource;
|
||||||
mod sitemap_resource;
|
mod sitemap_resource;
|
||||||
|
mod temporary_redirect_resource;
|
||||||
|
|
||||||
pub use self::article_redirect_resource::ArticleRedirectResource;
|
pub use self::article_redirect_resource::ArticleRedirectResource;
|
||||||
pub use self::article_resource::ArticleResource;
|
pub use self::article_resource::ArticleResource;
|
||||||
pub use self::changes_resource::ChangesResource;
|
pub use self::changes_resource::ChangesResource;
|
||||||
pub use self::new_article_resource::NewArticleResource;
|
pub use self::new_article_resource::NewArticleResource;
|
||||||
pub use self::sitemap_resource::SitemapResource;
|
pub use self::sitemap_resource::SitemapResource;
|
||||||
|
pub use self::temporary_redirect_resource::TemporaryRedirectResource;
|
||||||
|
|
46
src/resources/temporary_redirect_resource.rs
Normal file
46
src/resources/temporary_redirect_resource.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use futures::{self, Future};
|
||||||
|
use hyper;
|
||||||
|
use hyper::header::Location;
|
||||||
|
use hyper::server::*;
|
||||||
|
|
||||||
|
use web::{Resource, ResponseFuture};
|
||||||
|
|
||||||
|
pub struct TemporaryRedirectResource {
|
||||||
|
location: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TemporaryRedirectResource {
|
||||||
|
pub fn new(location: String) -> Self {
|
||||||
|
Self { location }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resource for TemporaryRedirectResource {
|
||||||
|
fn allow(&self) -> Vec<hyper::Method> {
|
||||||
|
use hyper::Method::*;
|
||||||
|
vec![Options, Head, Get, Put, Post]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn head(&self) -> ResponseFuture {
|
||||||
|
Box::new(futures::finished(Response::new()
|
||||||
|
.with_status(hyper::StatusCode::TemporaryRedirect)
|
||||||
|
.with_header(Location::new(self.location.clone()))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self: Box<Self>) -> ResponseFuture {
|
||||||
|
Box::new(self.head()
|
||||||
|
.and_then(move |head| {
|
||||||
|
Ok(head
|
||||||
|
.with_body(format!("Moved to {}", self.location)))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put(self: Box<Self>, _body: hyper::Body, _identity: Option<String>) -> ResponseFuture {
|
||||||
|
Box::new(self.head()
|
||||||
|
.and_then(move |head| {
|
||||||
|
Ok(head
|
||||||
|
.with_body(format!("Moved to {}", self.location)))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ impl WikiLookup {
|
||||||
Box::new(
|
Box::new(
|
||||||
done(pagination::from_str(query.unwrap_or("")).map_err(Into::into))
|
done(pagination::from_str(query.unwrap_or("")).map_err(Into::into))
|
||||||
.and_then(move |pagination| ChangesResource::new(state, pagination))
|
.and_then(move |pagination| ChangesResource::new(state, pagination))
|
||||||
.and_then(|changes_resource| Ok(Some(Box::new(changes_resource) as BoxResource)))
|
.and_then(|resource| Ok(Some(resource)))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
("_new", None) =>
|
("_new", None) =>
|
||||||
|
|
Loading…
Reference in a new issue