diff --git a/assets/style.css b/assets/style.css index 0a35f44..dd172ed 100644 --- a/assets/style.css +++ b/assets/style.css @@ -170,21 +170,21 @@ footer { "Droid Sans", "Helvetica Neue", sans-serif; } -footer ul { +ul.dense { list-style: none; padding: 0; } -footer li { +ul.dense>li { display: inline; } -footer li::after { +ul.dense>li::after { content: "\00B7"; margin: 0 12px; } -footer li:last-child::after { +ul.dense>li:last-child::after { content: ""; margin: 0; } diff --git a/src/main.rs b/src/main.rs index d8775e6..8a3a5e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ mod new_article_resource; mod rendering; mod schema; mod site; +mod sitemap_resource; mod state; mod web; mod wiki_lookup; diff --git a/src/sitemap_resource.rs b/src/sitemap_resource.rs new file mode 100644 index 0000000..61a8f02 --- /dev/null +++ b/src/sitemap_resource.rs @@ -0,0 +1,69 @@ +use futures::{self, Future}; +use hyper; +use hyper::header::ContentType; +use hyper::server::*; + +use assets::StyleCss; +use mimes::*; +use site::Layout; +use state::State; +use web::{Resource, ResponseFuture}; + +pub struct SitemapResource { + state: State, +} + +impl SitemapResource { + pub fn new(state: State) -> Self { + SitemapResource { state } + } +} + +impl Resource for SitemapResource { + fn allow(&self) -> Vec { + use hyper::Method::*; + vec![Options, Head, Get] + } + + fn head(&self) -> ResponseFuture { + Box::new(futures::finished(Response::new() + .with_status(hyper::StatusCode::Ok) + .with_header(ContentType(TEXT_HTML.clone())) + )) + } + + fn get(self: Box) -> ResponseFuture { + #[derive(BartDisplay)] + #[template="templates/sitemap.html"] + struct Template<'a> { + articles: &'a [ArticleReference], + } + + struct ArticleReference { + link: String, + title: String, + } + + let data = self.state.get_latest_article_revision_stubs(); + let head = self.head(); + + Box::new(data.join(head) + .and_then(move |(articles, head)| { + use std::iter::Iterator; + + let articles = &articles.into_iter().map(|x| { + ArticleReference { + link: if x.slug.is_empty() { ".".to_owned() } else { x.slug }, + title: x.title, + } + }).collect::>(); + + Ok(head + .with_body(Layout { + title: "Sitemap", + body: &Template { articles }, + style_css_checksum: StyleCss::checksum(), + }.to_string())) + })) + } +} diff --git a/src/state.rs b/src/state.rs index ab70b97..7e3a0d8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -129,6 +129,28 @@ impl State { }) } + pub fn get_latest_article_revision_stubs(&self) -> CpuFuture, Error> { + let connection_pool = self.connection_pool.clone(); + + self.cpu_pool.spawn_fn(move || { + use schema::article_revisions; + + Ok(article_revisions::table + .filter(article_revisions::latest.eq(true)) + .order(article_revisions::title.asc()) + .select(( + article_revisions::sequence_number, + article_revisions::article_id, + article_revisions::revision, + article_revisions::created, + article_revisions::slug, + article_revisions::title, + article_revisions::latest, + )) + .load(&*connection_pool.get()?)?) + }) + } + pub fn lookup_slug(&self, slug: String) -> CpuFuture { #[derive(Queryable)] struct ArticleRevisionStub { diff --git a/src/wiki_lookup.rs b/src/wiki_lookup.rs index a1f6ca2..4f9a293 100644 --- a/src/wiki_lookup.rs +++ b/src/wiki_lookup.rs @@ -7,6 +7,7 @@ use article_redirect_resource::ArticleRedirectResource; use article_resource::ArticleResource; use assets::*; use new_article_resource::NewArticleResource; +use sitemap_resource::SitemapResource; use state::State; use web::{Lookup, Resource}; @@ -27,6 +28,13 @@ lazy_static! { ) as ResourceFn ); + lookup_map.insert( + "/_sitemap".to_string(), + Box::new(|state: &State| + Box::new(SitemapResource::new(state.clone())) as BoxResource + ) as ResourceFn + ); + lookup_map.insert( "/_new".to_string(), Box::new(|state: &State| diff --git a/templates/article_revision.html b/templates/article_revision.html index 84ec576..e08fc9c 100644 --- a/templates/article_revision.html +++ b/templates/article_revision.html @@ -32,7 +32,7 @@