Start tracking authors for edits. #6

This commit is contained in:
Magnus Hoff 2017-10-18 16:33:21 +02:00
parent 6067ed8ddd
commit c85715c969
11 changed files with 28 additions and 16 deletions

View file

@ -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 {

View file

@ -0,0 +1,3 @@
ALTER TABLE article_revisions ADD COLUMN author TEXT CHECK (author != '');
CREATE INDEX author_lookup ON article_revisions (author);

View file

@ -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;

View file

@ -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>,
} }

View file

@ -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

View file

@ -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"))
) )
}) })

View file

@ -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()

View file

@ -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()))
} }
}, },

View file

@ -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)

View file

@ -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};