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])
|
.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 {
|
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 bart_derive;
|
||||||
#[macro_use] extern crate diesel;
|
#[macro_use] extern crate diesel;
|
||||||
#[macro_use] extern crate diesel_codegen;
|
#[macro_use] extern crate diesel_codegen;
|
||||||
|
#[macro_use] extern crate hyper;
|
||||||
#[macro_use] extern crate lazy_static;
|
#[macro_use] extern crate lazy_static;
|
||||||
#[macro_use] extern crate serde_derive;
|
#[macro_use] extern crate serde_derive;
|
||||||
#[macro_use] extern crate static_resource_derive;
|
#[macro_use] extern crate static_resource_derive;
|
||||||
|
@ -11,7 +12,6 @@ extern crate chrono;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate futures_cpupool;
|
extern crate futures_cpupool;
|
||||||
extern crate hyper;
|
|
||||||
extern crate percent_encoding;
|
extern crate percent_encoding;
|
||||||
extern crate pulldown_cmark;
|
extern crate pulldown_cmark;
|
||||||
extern crate r2d2;
|
extern crate r2d2;
|
||||||
|
|
|
@ -13,6 +13,8 @@ pub struct ArticleRevision {
|
||||||
pub body: String,
|
pub body: String,
|
||||||
|
|
||||||
pub latest: bool,
|
pub latest: bool,
|
||||||
|
|
||||||
|
pub author: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Queryable)]
|
#[derive(Debug, Queryable)]
|
||||||
|
@ -27,4 +29,6 @@ pub struct ArticleRevisionStub {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|
||||||
pub latest: bool,
|
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()
|
Box::new(self.head()
|
||||||
.and_then(move |head| {
|
.and_then(move |head| {
|
||||||
Ok(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
|
// TODO Check incoming Content-Type
|
||||||
|
|
||||||
use chrono::{TimeZone, Local};
|
use chrono::{TimeZone, Local};
|
||||||
|
@ -120,7 +120,7 @@ impl Resource for ArticleResource {
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
})
|
})
|
||||||
.and_then(move |update: UpdateArticle| {
|
.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| {
|
.and_then(|updated| {
|
||||||
futures::finished(Response::new()
|
futures::finished(Response::new()
|
||||||
|
@ -134,7 +134,7 @@ impl Resource for ArticleResource {
|
||||||
title: &updated.title,
|
title: &updated.title,
|
||||||
rendered: render_markdown(&updated.body),
|
rendered: render_markdown(&updated.body),
|
||||||
}.to_string(),
|
}.to_string(),
|
||||||
created: &Local.from_utc_datetime(&updated.created).to_string(),
|
created: &Local.from_utc_datetime(&updated.created).to_rfc2822(),
|
||||||
}).expect("Should never fail"))
|
}).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
|
// TODO Check incoming Content-Type
|
||||||
|
|
||||||
use chrono::{TimeZone, Local};
|
use chrono::{TimeZone, Local};
|
||||||
|
@ -135,7 +135,7 @@ impl Resource for NewArticleResource {
|
||||||
// TODO Check that update.base_revision == NDASH
|
// TODO Check that update.base_revision == NDASH
|
||||||
// ... which seems silly. But there should be a mechanism to indicate that
|
// ... which seems silly. But there should be a mechanism to indicate that
|
||||||
// the client is actually trying to create a new article
|
// 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| {
|
.and_then(|updated| {
|
||||||
futures::finished(Response::new()
|
futures::finished(Response::new()
|
||||||
|
|
|
@ -87,9 +87,13 @@ impl Service for Site {
|
||||||
type Future = Box<futures::Future<Item = Response, Error = Self::Error>>;
|
type Future = Box<futures::Future<Item = Response, Error = Self::Error>>;
|
||||||
|
|
||||||
fn call(&self, req: Request) -> Self::Future {
|
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);
|
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 base = root_base_from_request_uri(uri.path());
|
||||||
let base2 = base.clone(); // Bah, stupid clone
|
let base2 = base.clone(); // Bah, stupid clone
|
||||||
|
|
||||||
|
@ -101,7 +105,7 @@ impl Service for Site {
|
||||||
Options => Box::new(futures::finished(resource.options())),
|
Options => Box::new(futures::finished(resource.options())),
|
||||||
Head => resource.head(),
|
Head => resource.head(),
|
||||||
Get => resource.get(),
|
Get => resource.get(),
|
||||||
Put => resource.put(body),
|
Put => resource.put(body, identity),
|
||||||
_ => Box::new(futures::finished(resource.method_not_allowed()))
|
_ => Box::new(futures::finished(resource.method_not_allowed()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,6 +35,7 @@ struct NewRevision<'a> {
|
||||||
slug: &'a str,
|
slug: &'a str,
|
||||||
title: &'a str,
|
title: &'a str,
|
||||||
body: &'a str,
|
body: &'a str,
|
||||||
|
author: Option<&'a str>,
|
||||||
latest: bool,
|
latest: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +118,7 @@ impl State {
|
||||||
article_revisions::slug,
|
article_revisions::slug,
|
||||||
article_revisions::title,
|
article_revisions::title,
|
||||||
article_revisions::latest,
|
article_revisions::latest,
|
||||||
|
article_revisions::author,
|
||||||
))
|
))
|
||||||
.into_boxed();
|
.into_boxed();
|
||||||
|
|
||||||
|
@ -146,6 +148,7 @@ impl State {
|
||||||
article_revisions::slug,
|
article_revisions::slug,
|
||||||
article_revisions::title,
|
article_revisions::title,
|
||||||
article_revisions::latest,
|
article_revisions::latest,
|
||||||
|
article_revisions::author,
|
||||||
))
|
))
|
||||||
.load(&*connection_pool.get()?)?)
|
.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>
|
-> CpuFuture<models::ArticleRevision, Error>
|
||||||
{
|
{
|
||||||
let connection_pool = self.connection_pool.clone();
|
let connection_pool = self.connection_pool.clone();
|
||||||
|
@ -239,6 +242,7 @@ impl State {
|
||||||
slug: &slug,
|
slug: &slug,
|
||||||
title: &title,
|
title: &title,
|
||||||
body: &body,
|
body: &body,
|
||||||
|
author: author.as_ref().map(|x| &**x),
|
||||||
latest: true,
|
latest: true,
|
||||||
})
|
})
|
||||||
.into(article_revisions::table)
|
.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>
|
-> CpuFuture<models::ArticleRevision, Error>
|
||||||
{
|
{
|
||||||
let connection_pool = self.connection_pool.clone();
|
let connection_pool = self.connection_pool.clone();
|
||||||
|
@ -288,6 +292,7 @@ impl State {
|
||||||
slug: &slug,
|
slug: &slug,
|
||||||
title: &title,
|
title: &title,
|
||||||
body: &body,
|
body: &body,
|
||||||
|
author: author.as_ref().map(|x| &**x),
|
||||||
latest: true,
|
latest: true,
|
||||||
})
|
})
|
||||||
.into(article_revisions::table)
|
.into(article_revisions::table)
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub trait Resource {
|
||||||
Box::new(futures::finished(self.method_not_allowed()))
|
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
|
where Self: 'static
|
||||||
{
|
{
|
||||||
use futures::{Future, Stream};
|
use futures::{Future, Stream};
|
||||||
|
|
Loading…
Reference in a new issue