Start tracking authors for edits. #6
This commit is contained in:
parent
6067ed8ddd
commit
c85715c969
11 changed files with 28 additions and 16 deletions
|
@ -94,10 +94,6 @@ pub fn static_resource(input: TokenStream) -> TokenStream {
|
|||
.with_body(body as &'static [u8])
|
||||
))
|
||||
}
|
||||
|
||||
fn put(self: Box<Self>, _body: ::hyper::Body) -> ResponseFuture {
|
||||
Box::new(::futures::finished(self.method_not_allowed()))
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics #name #ty_generics #where_clause {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE article_revisions ADD COLUMN author TEXT CHECK (author != '');
|
||||
|
||||
CREATE INDEX author_lookup ON article_revisions (author);
|
|
@ -3,6 +3,7 @@
|
|||
#[macro_use] extern crate bart_derive;
|
||||
#[macro_use] extern crate diesel;
|
||||
#[macro_use] extern crate diesel_codegen;
|
||||
#[macro_use] extern crate hyper;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
#[macro_use] extern crate static_resource_derive;
|
||||
|
@ -11,7 +12,6 @@ extern crate chrono;
|
|||
extern crate clap;
|
||||
extern crate futures;
|
||||
extern crate futures_cpupool;
|
||||
extern crate hyper;
|
||||
extern crate percent_encoding;
|
||||
extern crate pulldown_cmark;
|
||||
extern crate r2d2;
|
||||
|
|
|
@ -13,6 +13,8 @@ pub struct ArticleRevision {
|
|||
pub body: String,
|
||||
|
||||
pub latest: bool,
|
||||
|
||||
pub author: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Queryable)]
|
||||
|
@ -27,4 +29,6 @@ pub struct ArticleRevisionStub {
|
|||
pub title: String,
|
||||
|
||||
pub latest: bool,
|
||||
|
||||
pub author: Option<String>,
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ impl Resource for ArticleRedirectResource {
|
|||
}))
|
||||
}
|
||||
|
||||
fn put(self: Box<Self>, _body: hyper::Body) -> ResponseFuture {
|
||||
fn put(self: Box<Self>, _body: hyper::Body, _identity: Option<String>) -> ResponseFuture {
|
||||
Box::new(self.head()
|
||||
.and_then(move |head| {
|
||||
Ok(head
|
||||
|
|
|
@ -83,7 +83,7 @@ impl Resource for ArticleResource {
|
|||
}))
|
||||
}
|
||||
|
||||
fn put(self: Box<Self>, body: hyper::Body) -> ResponseFuture {
|
||||
fn put(self: Box<Self>, body: hyper::Body, identity: Option<String>) -> ResponseFuture {
|
||||
// TODO Check incoming Content-Type
|
||||
|
||||
use chrono::{TimeZone, Local};
|
||||
|
@ -120,7 +120,7 @@ impl Resource for ArticleResource {
|
|||
.map_err(Into::into)
|
||||
})
|
||||
.and_then(move |update: UpdateArticle| {
|
||||
self.state.update_article(self.article_id, update.base_revision, update.title, update.body)
|
||||
self.state.update_article(self.article_id, update.base_revision, update.title, update.body, identity)
|
||||
})
|
||||
.and_then(|updated| {
|
||||
futures::finished(Response::new()
|
||||
|
@ -134,7 +134,7 @@ impl Resource for ArticleResource {
|
|||
title: &updated.title,
|
||||
rendered: render_markdown(&updated.body),
|
||||
}.to_string(),
|
||||
created: &Local.from_utc_datetime(&updated.created).to_string(),
|
||||
created: &Local.from_utc_datetime(&updated.created).to_rfc2822(),
|
||||
}).expect("Should never fail"))
|
||||
)
|
||||
})
|
||||
|
|
|
@ -94,7 +94,7 @@ impl Resource for NewArticleResource {
|
|||
}))
|
||||
}
|
||||
|
||||
fn put(self: Box<Self>, body: hyper::Body) -> ResponseFuture {
|
||||
fn put(self: Box<Self>, body: hyper::Body, identity: Option<String>) -> ResponseFuture {
|
||||
// TODO Check incoming Content-Type
|
||||
|
||||
use chrono::{TimeZone, Local};
|
||||
|
@ -135,7 +135,7 @@ impl Resource for NewArticleResource {
|
|||
// TODO Check that update.base_revision == NDASH
|
||||
// ... which seems silly. But there should be a mechanism to indicate that
|
||||
// the client is actually trying to create a new article
|
||||
self.state.create_article(self.slug.clone(), arg.title, arg.body)
|
||||
self.state.create_article(self.slug.clone(), arg.title, arg.body, identity)
|
||||
})
|
||||
.and_then(|updated| {
|
||||
futures::finished(Response::new()
|
||||
|
|
|
@ -87,9 +87,13 @@ impl Service for Site {
|
|||
type Future = Box<futures::Future<Item = Response, Error = Self::Error>>;
|
||||
|
||||
fn call(&self, req: Request) -> Self::Future {
|
||||
let (method, uri, _http_version, _headers, body) = req.deconstruct();
|
||||
let (method, uri, _http_version, headers, body) = req.deconstruct();
|
||||
|
||||
println!("{} {}", method, uri);
|
||||
|
||||
header! { (XIdentity, "X-Identity") => [String] }
|
||||
let identity: Option<String> = headers.get().map(|x: &XIdentity| x.to_string());
|
||||
|
||||
let base = root_base_from_request_uri(uri.path());
|
||||
let base2 = base.clone(); // Bah, stupid clone
|
||||
|
||||
|
@ -101,7 +105,7 @@ impl Service for Site {
|
|||
Options => Box::new(futures::finished(resource.options())),
|
||||
Head => resource.head(),
|
||||
Get => resource.get(),
|
||||
Put => resource.put(body),
|
||||
Put => resource.put(body, identity),
|
||||
_ => Box::new(futures::finished(resource.method_not_allowed()))
|
||||
}
|
||||
},
|
||||
|
|
|
@ -35,6 +35,7 @@ struct NewRevision<'a> {
|
|||
slug: &'a str,
|
||||
title: &'a str,
|
||||
body: &'a str,
|
||||
author: Option<&'a str>,
|
||||
latest: bool,
|
||||
}
|
||||
|
||||
|
@ -117,6 +118,7 @@ impl State {
|
|||
article_revisions::slug,
|
||||
article_revisions::title,
|
||||
article_revisions::latest,
|
||||
article_revisions::author,
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
|
@ -146,6 +148,7 @@ impl State {
|
|||
article_revisions::slug,
|
||||
article_revisions::title,
|
||||
article_revisions::latest,
|
||||
article_revisions::author,
|
||||
))
|
||||
.load(&*connection_pool.get()?)?)
|
||||
})
|
||||
|
@ -195,7 +198,7 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn update_article(&self, article_id: i32, base_revision: i32, title: String, body: String)
|
||||
pub fn update_article(&self, article_id: i32, base_revision: i32, title: String, body: String, author: Option<String>)
|
||||
-> CpuFuture<models::ArticleRevision, Error>
|
||||
{
|
||||
let connection_pool = self.connection_pool.clone();
|
||||
|
@ -239,6 +242,7 @@ impl State {
|
|||
slug: &slug,
|
||||
title: &title,
|
||||
body: &body,
|
||||
author: author.as_ref().map(|x| &**x),
|
||||
latest: true,
|
||||
})
|
||||
.into(article_revisions::table)
|
||||
|
@ -253,7 +257,7 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn create_article(&self, target_slug: Option<String>, title: String, body: String)
|
||||
pub fn create_article(&self, target_slug: Option<String>, title: String, body: String, author: Option<String>)
|
||||
-> CpuFuture<models::ArticleRevision, Error>
|
||||
{
|
||||
let connection_pool = self.connection_pool.clone();
|
||||
|
@ -288,6 +292,7 @@ impl State {
|
|||
slug: &slug,
|
||||
title: &title,
|
||||
body: &body,
|
||||
author: author.as_ref().map(|x| &**x),
|
||||
latest: true,
|
||||
})
|
||||
.into(article_revisions::table)
|
||||
|
|
|
@ -21,7 +21,7 @@ pub trait Resource {
|
|||
Box::new(futures::finished(self.method_not_allowed()))
|
||||
}
|
||||
|
||||
fn put(self: Box<Self>, body: hyper::Body) -> ResponseFuture
|
||||
fn put(self: Box<Self>, body: hyper::Body, _identity: Option<String>) -> ResponseFuture
|
||||
where Self: 'static
|
||||
{
|
||||
use futures::{Future, Stream};
|
||||
|
|
Loading…
Reference in a new issue