Skip to content

Commit

Permalink
A whole bunch of polish
Browse files Browse the repository at this point in the history
* Submitted comments now appear in the document when submitted
* Permissions handling has been streamlined and moved out of templates
where possible
* Comrak/markdown settings have been set as a constant, some previously
disabled extensions have been enabled
* Unpublished articles are no longer viewable by users without editing
rights
* API points for serving html of a single comment have been added
* /api/comments/submit now returns the submitted comment
* Javascript has been moved out of article.html to a separate file
* More unobtrusive javascript
* CSS uses tabs instead of spaces
* Document title is set for article pages
* Article editing page remembers published status in checkbox
* Added copyright notice to bottom of pages
* Bumped version to 0.1.3
  • Loading branch information
agraven committed Apr 8, 2020
1 parent 3288dfb commit 77af1f5
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 307 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
**/*.rs.bk
*~
.env
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "mogger"
description = "A minimalistic blogging engine"
description = "Simple blogging engine"
homepage = "https://github.com/agraven/mogger"
license = "AGPL-3.0-or-later"
version = "0.1.2"
version = "0.1.3"
authors = ["Amanda P. Graven <[email protected]>"]
edition = "2018"
readme = "README.md"
Expand Down
1 change: 1 addition & 0 deletions debian/postinst
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
set -e

adduser --system --group --home /var/lib/mogger --no-create-home mogger
systemctl daemon-reload
36 changes: 33 additions & 3 deletions src/article.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chrono::naive::NaiveDateTime;
use comrak::{markdown_to_html, ComrakOptions};
use comrak::markdown_to_html;
use diesel::pg::PgConnection as Connection;
use diesel::prelude::*;
use diesel::result::Error as DieselError;
Expand All @@ -8,7 +8,7 @@ use diesel::RunQueryDsl;

use crate::schema::articles;

use crate::user::User;
use crate::user::{Permission, Session, User};

const PREVIEW_LEN: usize = 500;
const DESCRIPTION_LEN: usize = 160;
Expand All @@ -33,6 +33,36 @@ pub struct Article {
}

impl Article {
/// Checks if the given session is authorized to view this article. Permission is granted if
/// the article is marked visible or the user has editing rights.
pub fn viewable(
&self,
session: Option<&Session>,
conn: &Connection,
) -> Result<bool, DieselError> {
if self.visible {
return Ok(true);
} else {
self.editable(session, conn)
}
}

/// Checks if the given session has permission to edit this article. Permission is granted if
/// the user has the EditForeignArticle permission, or owns this article and has the
/// EditArticle permission.
pub fn editable(
&self,
session: Option<&Session>,
conn: &Connection,
) -> Result<bool, DieselError> {
if let Some(session) = session {
Ok(session.allowed(Permission::EditForeignArticle, conn)?
|| session.allowed(Permission::EditArticle, conn)? && self.author == session.user)
} else {
Ok(false)
}
}

/// Get the user who submitted this article
pub fn user(&self, connection: &Connection) -> Result<User, DieselError> {
crate::schema::users::dsl::users
Expand All @@ -42,7 +72,7 @@ impl Article {

/// Return the marked up version of the article's body.
pub fn formatted(&self) -> String {
markdown_to_html(&self.content, &ComrakOptions::default())
markdown_to_html(&self.content, &crate::COMRAK_OPTS)
}

/// Get a short slice of the article's contents.
Expand Down
48 changes: 41 additions & 7 deletions src/comment.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use chrono::NaiveDateTime;
use comrak::{markdown_to_html, ComrakOptions};
use comrak::markdown_to_html;
use diesel::{pg::PgConnection as Connection, prelude::*, result::Error as DieselError, Queryable};

use crate::{schema::comments, user};
use crate::{
schema::comments,
user::{self, Permission, Session},
};

#[derive(Clone, Debug, Serialize, Deserialize, Queryable, Identifiable)]
pub struct Comment {
Expand Down Expand Up @@ -52,8 +55,38 @@ pub struct Node {
}

impl Comment {
pub fn viewable(
&self,
session: Option<&Session>,
conn: &Connection,
) -> Result<bool, DieselError> {
if self.visible {
Ok(true)
} else {
self.editable(session, conn)
}
}

pub fn editable(
&self,
session: Option<&Session>,
conn: &Connection,
) -> Result<bool, DieselError> {
if let Some(session) = session {
Ok(session.allowed(Permission::EditForeignComment, conn)?
|| session.allowed(Permission::EditComment, conn)?
&& self
.author
.as_ref()
.map(|a| a == &session.user)
.unwrap_or(false))
} else {
Ok(false)
}
}

pub fn formatted(&self) -> String {
markdown_to_html(&self.content, &ComrakOptions::default())
markdown_to_html(&self.content, &crate::COMRAK_OPTS)
}

pub fn author(&self, connection: &Connection) -> Result<String, failure::Error> {
Expand Down Expand Up @@ -151,10 +184,11 @@ pub fn view_single(connection: &Connection, id: i32) -> Result<Option<Comment>,
dsl::comments.find(id).first(connection).optional()
}

pub fn submit(connection: &Connection, comment: NewComment) -> Result<usize, DieselError> {
diesel::insert_into(comments::table)
pub fn submit(connection: &Connection, comment: NewComment) -> Result<Comment, DieselError> {
let sumbitted = diesel::insert_into(comments::table)
.values(&comment)
.execute(connection)
.get_result(connection)?;
Ok(sumbitted)
}

pub fn edit(
Expand Down Expand Up @@ -211,7 +245,7 @@ mod tests {
id,
parent,
article: 1,
author: String::from("test_author"),
author: Some(String::from("test_author")),
name: None,
content: String::from("Test article"),
date: Utc::now().naive_utc(),
Expand Down
20 changes: 12 additions & 8 deletions src/document/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use askama::Template;
use cookie::Cookie;
use diesel::PgConnection as Connection;
use gotham::{
helpers::http::response::create_temporary_redirect as temp_redirect,
helpers::http::response::{create_empty_response, create_temporary_redirect as temp_redirect},
state::{FromState, State},
};
use hyper::{header, StatusCode};
Expand Down Expand Up @@ -62,11 +62,11 @@ pub struct ArticleTemplate<'a> {
#[derive(Template)]
#[template(path = "comments.html", escape = "none")]
pub struct CommentTemplate<'a> {
comment: &'a comment::Comment,
children: Vec<CommentTemplate<'a>>,
connection: &'a Connection,
session: Option<&'a Session>,
article_id: i32,
pub comment: &'a comment::Comment,
pub children: Vec<CommentTemplate<'a>>,
pub connection: &'a Connection,
pub session: Option<&'a Session>,
pub article_id: i32,
}

#[derive(Template, Clone)]
Expand Down Expand Up @@ -110,8 +110,12 @@ pub fn article(state: &State) -> DocumentResult {
let session = Session::try_borrow_from(state);

let article = article::view(connection, &id)?;
let id = article.id;
let comments = comment::list(connection, id)?;
// Return a 404 if the user isn't allowed to view the article
if !article.viewable(session, connection)? {
return Ok(create_empty_response(state, StatusCode::NOT_FOUND));
}

let comments = comment::list(connection, article.id)?;
let comments_template = comments
.iter()
.map(|child| CommentTemplate::from_node(child, connection, session, article.id))
Expand Down
40 changes: 24 additions & 16 deletions src/handler/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use mime::APPLICATION_JSON as JSON;
use crate::{
comment,
comment::{CommentChanges, NewComment},
document::TemplateExt,
handler::articles::ArticlePath,
user::{
Permission::{DeleteComment, DeleteForeignComment, EditComment, EditForeignComment},
Expand Down Expand Up @@ -57,7 +58,7 @@ pub fn single(state: &State) -> Result<Response<Body>, failure::Error> {
Ok(create_response(&state, StatusCode::OK, JSON, content))
}

pub fn render(state: &State) -> Result<Response<Body>, failure::Error> {
pub fn render_content(state: &State) -> Result<Response<Body>, failure::Error> {
let connection = &DbConnection::borrow_from(state).lock()?;
let id = CommentPath::borrow_from(&state).id;

Expand All @@ -69,12 +70,25 @@ pub fn render(state: &State) -> Result<Response<Body>, failure::Error> {
comment.formatted(),
))
} else {
Ok(create_response(
&state,
StatusCode::NOT_FOUND,
mime::TEXT_PLAIN,
"Not found",
))
Ok(create_empty_response(&state, StatusCode::NOT_FOUND))
}
}

pub fn render(state: &State) -> Result<Response<Body>, failure::Error> {
let connection = &DbConnection::borrow_from(state).lock()?;
let id = CommentPath::borrow_from(&state).id;

if let Some(comment) = comment::view_single(connection, id)? {
let template = crate::document::index::CommentTemplate {
comment: &comment,
children: Vec::new(),
connection: connection,
session: Session::try_borrow_from(state),
article_id: comment.article,
};
Ok(template.to_response(state))
} else {
Ok(create_empty_response(&state, StatusCode::NOT_FOUND))
}
}

Expand All @@ -83,8 +97,9 @@ pub fn submit(state: &State, post: Vec<u8>) -> Result<Response<Body>, failure::E

let new: NewComment = serde_json::from_slice(&post)?;

comment::submit(connection, new)?;
Ok(create_empty_response(&state, StatusCode::OK))
let submitted = comment::submit(connection, new)?;
let content = serde_json::to_string(&submitted)?;
Ok(create_response(&state, StatusCode::OK, JSON, content))
}

pub fn edit(state: &State, post: Vec<u8>) -> Result<Response<Body>, failure::Error> {
Expand Down Expand Up @@ -123,13 +138,6 @@ pub fn delete(state: &State) -> Result<Response<Body>, failure::Error> {
_ => return Err(failure::err_msg("Permission denied")),
};

// FIXME
// Check for same user
/*let comment = comment::view_single(connection, id)?;
if comment.and_then(|c| c.author) == session.map(|s| s.user.clone()) {
return Err(err_msg("Unauthorized"));
}*/

comment::delete(conn, id)?;
Ok(create_empty_response(&state, StatusCode::OK))
}
Expand Down
23 changes: 23 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub mod handler;
pub mod schema;
pub mod user;

use comrak::ComrakOptions;
pub use diesel::pg::PgConnection as Connection;
use gotham::{
middleware::cookie::CookieParser,
Expand Down Expand Up @@ -111,6 +112,24 @@ impl DbConnection {
}
}

pub const COMRAK_OPTS: ComrakOptions = ComrakOptions {
hardbreaks: false,
smart: false,
github_pre_lang: true,
width: 0,
default_info_string: None,
unsafe_: false,
ext_strikethrough: true,
ext_tagfilter: false,
ext_table: true,
ext_autolink: true,
ext_tasklist: false,
ext_superscript: true,
ext_header_ids: None,
ext_footnotes: true,
ext_description_lists: false,
};

/// Builds the request router
fn router(settings: &Settings) -> Router {
// The directory static assets are served from. Is:
Expand Down Expand Up @@ -211,6 +230,10 @@ fn router(settings: &Settings) -> Router {
.with_path_extractor::<comments::CommentPath>()
.to(handler!(comments::single));

route
.get("/render-content/:id")
.with_path_extractor::<comments::CommentPath>()
.to(handler!(comments::render_content));
route
.get("/render/:id")
.with_path_extractor::<comments::CommentPath>()
Expand Down
Loading

0 comments on commit 77af1f5

Please sign in to comment.