Add basic /_changes page

This commit is contained in:
Magnus Hoff 2017-10-03 10:37:18 +02:00
parent 370cbd0c24
commit f22ffc112a
6 changed files with 173 additions and 0 deletions

82
src/changes_resource.rs Normal file
View file

@ -0,0 +1,82 @@
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 ChangesResource {
state: State,
before: Option<i32>,
}
impl ChangesResource {
pub fn new(state: State, before: Option<i32>) -> Self {
Self { state, before }
}
}
impl Resource for ChangesResource {
fn allow(&self) -> Vec<hyper::Method> {
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<Self>) -> ResponseFuture {
use chrono::{TimeZone, Local};
struct Row {
article_id: i32,
revision: i32,
created: String,
slug: String,
title: String,
latest: bool,
}
#[derive(BartDisplay)]
#[template="templates/changes.html"]
struct Template<'a> {
changes: &'a [Row],
}
let data = self.state.get_article_revision_stubs(self.before, 30);
let head = self.head();
Box::new(data.join(head)
.and_then(move |(data, head)| {
use std::iter::Iterator;
let changes = &data.into_iter().map(|x| {
Row {
article_id: x.article_id,
revision: x.revision,
created: Local.from_utc_datetime(&x.created).to_string(),
slug: x.slug,
title: x.title,
latest: x.latest,
}
}).collect::<Vec<_>>();
Ok(head
.with_body(Layout {
title: "Changes",
body: &Template { changes },
style_css_checksum: StyleCss::checksum(),
}.to_string()))
}))
}
}

View file

@ -26,6 +26,7 @@ use std::net::SocketAddr;
mod article_redirect_resource;
mod article_resource;
mod assets;
mod changes_resource;
mod db;
mod mimes;
mod models;

View file

@ -14,3 +14,17 @@ pub struct ArticleRevision {
pub latest: bool,
}
#[derive(Debug, Queryable)]
pub struct ArticleRevisionStub {
pub sequence_number: i32,
pub article_id: i32,
pub revision: i32,
pub created: chrono::NaiveDateTime,
pub slug: String,
pub title: String,
pub latest: bool,
}

View file

@ -100,6 +100,35 @@ impl State {
})
}
pub fn get_article_revision_stubs(&self, before: Option<i32>, limit: i32) -> CpuFuture<Vec<models::ArticleRevisionStub>, Error> {
let connection_pool = self.connection_pool.clone();
self.cpu_pool.spawn_fn(move || {
use schema::article_revisions;
let query = article_revisions::table
.order(article_revisions::sequence_number.desc())
.limit(limit as i64)
.select((
article_revisions::sequence_number,
article_revisions::article_id,
article_revisions::revision,
article_revisions::created,
article_revisions::slug,
article_revisions::title,
article_revisions::latest,
))
.into_boxed();
let query = match before {
Some(before) => query.filter(article_revisions::sequence_number.lt(before)),
None => query
};
Ok(query.load(&*connection_pool.get()?)?)
})
}
pub fn lookup_slug(&self, slug: String) -> CpuFuture<SlugLookup, Error> {
#[derive(Queryable)]
struct ArticleRevisionStub {

View file

@ -17,6 +17,16 @@ lazy_static! {
static ref LOOKUP_MAP: HashMap<String, ResourceFn> = {
let mut lookup_map = HashMap::new();
use changes_resource::ChangesResource;
lookup_map.insert(
"/_changes".to_string(),
Box::new(|state: &State|
// TODO Use query arguments to fill in the `before` parameter below
Box::new(ChangesResource::new(state.clone(), None)) as BoxResource
) as ResourceFn
);
lookup_map.insert(
"/_new".to_string(),
Box::new(|state: &State|

37
templates/changes.html Normal file
View file

@ -0,0 +1,37 @@
<div class="container">
<header>
<h1>Changes</h1>
</header>
<article>
<table>
<tr>
<th>Title</th>
<th>Slug</th>
<th>Article ID</th>
<th>Revision</th>
<th>Created</th>
</tr>
{{#changes}}
<tr>
<td>
{{#.latest?}}<a href="{{#..slug.is_empty()?}}.{{/..slug.is_empty()}}{{..slug}}">{{/.latest}}
{{.title}}
{{#.latest?}}</a>{{/.latest}}
</td>
<td>{{#.slug.is_empty()?}}/{{/.slug.is_empty()}}{{.slug}}</td>
<td>{{.article_id}}</td>
<td>{{.revision}}</td>
<td>{{.created}}</td>
</tr>
{{/changes}}
</table>
</article>
</div>
<footer>
<ul>
<li><a href="_new">Create article</a></li>
</ul>
<p>Powered by <a href="https://github.com/maghoff/sausagewiki">Sausagewiki</a></p>
</footer>