diff --git a/migrations/20170820204425_add_articles/down.sql b/migrations/20170820204425_add_articles/down.sql new file mode 100644 index 0000000..b17480e --- /dev/null +++ b/migrations/20170820204425_add_articles/down.sql @@ -0,0 +1,2 @@ +DROP TABLE article_revisions; +DROP TABLE articles; diff --git a/migrations/20170820204425_add_articles/up.sql b/migrations/20170820204425_add_articles/up.sql new file mode 100644 index 0000000..b4eed77 --- /dev/null +++ b/migrations/20170820204425_add_articles/up.sql @@ -0,0 +1,16 @@ +CREATE TABLE articles ( + id INTEGER PRIMARY KEY NOT NULL +); + +CREATE TABLE article_revisions ( + article_id INTEGER NOT NULL, + revision INTEGER NOT NULL, + created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + title TEXT NOT NULL, + body TEXT NOT NULL, + + PRIMARY KEY (article_id, revision), + FOREIGN KEY (article_id) REFERENCES articles(id) +); + diff --git a/src/models.rs b/src/models.rs index a504922..64893d2 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,9 +1,9 @@ use chrono; #[derive(BartDisplay, Debug, Queryable)] -#[template="templates/article.html"] -pub struct Article { - pub id: i32, +#[template="templates/article_revision.html"] +pub struct ArticleRevision { + pub article_id: i32, pub revision: i32, pub created: chrono::NaiveDateTime, diff --git a/src/site.rs b/src/site.rs index a38d2e9..68b3f90 100644 --- a/src/site.rs +++ b/src/site.rs @@ -59,41 +59,55 @@ impl Service for Site { ).boxed() } else { assert!(path.starts_with("/")); - match self.state.find_article_by_slug(&path[1..]) { - Ok(Some(article)) => { - futures::finished( - Response::new() - .with_header(ContentType(TEXT_HTML.clone())) - .with_body(Layout { - title: &article.title, - body: &article - }.to_string()) - .with_status(hyper::StatusCode::Ok) - ).boxed() - }, - Ok(None) => { - futures::finished( - Response::new() - .with_header(ContentType(TEXT_HTML.clone())) - .with_body(Layout { - title: "Not found", - body: &NotFound, - }.to_string()) - .with_status(hyper::StatusCode::NotFound) - ).boxed() - }, - Err(err) => { - eprintln!("Error while servicing request {} {}:\n{:#?}", req.method(), req.path(), err); - futures::finished( - Response::new() - .with_header(ContentType(TEXT_HTML.clone())) - .with_body(Layout { - title: "Internal server error", - body: &InternalServerError, - }.to_string()) - .with_status(hyper::StatusCode::InternalServerError) - ).boxed() + let slug = &path[1..]; + if let Ok(article_id) = slug.parse() { + match self.state.get_article_revision_by_id(article_id) { + Ok(Some(article)) => { + futures::finished( + Response::new() + .with_header(ContentType(TEXT_HTML.clone())) + .with_body(Layout { + title: &article.title, + body: &article + }.to_string()) + .with_status(hyper::StatusCode::Ok) + ).boxed() + }, + Ok(None) => { + futures::finished( + Response::new() + .with_header(ContentType(TEXT_HTML.clone())) + .with_body(Layout { + title: "Not found", + body: &NotFound, + }.to_string()) + .with_status(hyper::StatusCode::NotFound) + ).boxed() + }, + Err(err) => { + eprintln!("Error while servicing request {} {}:\n{:#?}", req.method(), req.path(), err); + futures::finished( + Response::new() + .with_header(ContentType(TEXT_HTML.clone())) + .with_body(Layout { + title: "Internal server error", + body: &InternalServerError, + }.to_string()) + .with_status(hyper::StatusCode::InternalServerError) + ).boxed() + } } + } else { + // slugs must be article IDs... for now + futures::finished( + Response::new() + .with_header(ContentType(TEXT_HTML.clone())) + .with_body(Layout { + title: "Not found", + body: &NotFound, + }.to_string()) + .with_status(hyper::StatusCode::NotFound) + ).boxed() } } } diff --git a/src/state.rs b/src/state.rs index ccd0ca6..d1c7375 100644 --- a/src/state.rs +++ b/src/state.rs @@ -2,6 +2,7 @@ use std; use chrono; use diesel::sqlite::SqliteConnection; +use diesel::prelude::*; use models; @@ -14,13 +15,24 @@ impl State { State { db_connection } } - pub fn find_article_by_slug(&self, slug: &str) -> Result, Box> { - Ok(Some(models::Article { - id: 0, + pub fn get_article_revision_by_slug(&self, slug: &str) -> Result, Box> { + Ok(Some(models::ArticleRevision { + article_id: 0, revision: 0, created: chrono::Local::now().naive_local(), title: slug.to_owned(), body: "Look at me!".to_owned(), })) } + + pub fn get_article_revision_by_id(&self, article_id: i32) -> Result, Box> { + use schema::article_revisions; + + Ok(article_revisions::table + .filter(article_revisions::article_id.eq(article_id)) + .order(article_revisions::revision.desc()) + .limit(1) + .load::(&self.db_connection)? + .pop()) + } } diff --git a/templates/article.html b/templates/article_revision.html similarity index 61% rename from templates/article.html rename to templates/article_revision.html index f2d8477..9f6afe7 100644 --- a/templates/article.html +++ b/templates/article_revision.html @@ -1,4 +1,4 @@ -

{{id}}-{{revision}}

+

{{article_id}}-{{revision}}

{{created}}

{{title}}