diff options
author | Vincent Ambo <tazjin@gmail.com> | 2018-04-15T21·09+0200 |
---|---|---|
committer | Vincent Ambo <tazjin@gmail.com> | 2018-04-15T21·09+0200 |
commit | 705097dab91c57524d2311dd839615840044437c (patch) | |
tree | 2b7763180fb25d3e85107a086b8fb1739e0e6688 | |
parent | 7a557865528d6dba78b4dcb90248623aa100f930 (diff) |
feat(handlers/render): Display edit form for user's own posts
Displays an edit form for posts that are owned by a user (which is currently defined as "email addresses match").
-rw-r--r-- | src/errors.rs | 3 | ||||
-rw-r--r-- | src/handlers.rs | 35 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/render.rs | 24 | ||||
-rw-r--r-- | templates/thread.html | 2 |
5 files changed, 63 insertions, 2 deletions
diff --git a/src/errors.rs b/src/errors.rs index 9de907430d6e..8345a9382f15 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -54,6 +54,9 @@ pub enum ConverseError { #[fail(display = "error occured running timer: {}", error)] Timer { error: tokio_timer::Error }, + #[fail(display = "user does not have permission to edit post {}", id)] + PostEditForbidden { id: i32 }, + // This variant is used as a catch-all for wrapping // actix-web-compatible response errors, such as the errors it // throws itself. diff --git a/src/handlers.rs b/src/handlers.rs index 8bfd3c1511e6..cbe4e4292b7c 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -189,6 +189,41 @@ pub fn reply_thread(state: State<AppState>, .responder() } +/// This handler presents the user with the form to edit a post. If +/// the user attempts to edit a post that they do not have access to, +/// they are currently ungracefully redirected back to the post +/// itself. +pub fn edit_form(state: State<AppState>, + mut req: HttpRequest<AppState>, + query: Path<GetPost>) -> ConverseResponse { + let author: Option<Author> = req.session().get(AUTHOR) + .unwrap_or_else(|_| None); + + state.db.send(query.into_inner()) + .flatten() + .from_err() + .and_then(move |post| { + if let Some(author) = author { + if author.email.eq(&post.author_email) { + return Ok(post); + } + } + + Err(ConverseError::PostEditForbidden { id: post.id }) + }) + .and_then(move |post| { + let edit_msg = EditPostPage { + id: post.id, + post: post.body, + }; + + state.renderer.send(edit_msg).from_err() + }) + .flatten() + .map(|page| HttpResponse::Ok().content_type(HTML).body(page)) + .responder() +} + /// This handler executes a full-text search on the forum database and /// displays the results to the user. pub fn search_forum(state: State<AppState>, diff --git a/src/main.rs b/src/main.rs index 8d81a670e0a2..55b19b0be7c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,6 +181,7 @@ fn start_http_server(base_url: String, .resource("/thread/submit", |r| r.method(Method::POST).with3(submit_thread)) .resource("/thread/reply", |r| r.method(Method::POST).with3(reply_thread)) .resource("/thread/{id}", |r| r.method(Method::GET).with3(forum_thread)) + .resource("/post/{id}/edit", |r| r.method(Method::GET).with3(edit_form)) .resource("/search", |r| r.method(Method::GET).with2(search_forum)) .resource("/oidc/login", |r| r.method(Method::GET).with(login)) .resource("/oidc/callback", |r| r.method(Method::POST).with3(callback)); diff --git a/src/render.rs b/src/render.rs index c0a2fe88e697..e02ac31ea98c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -200,7 +200,7 @@ impl Handler<NewThreadPage> for Renderer { type Result = Result<String>; fn handle(&mut self, msg: NewThreadPage, _: &mut Self::Context) -> Self::Result { - let ctx: FormContext = FormContext { + let ctx = FormContext { alerts: msg.alerts, title: msg.title, post: msg.post, @@ -210,6 +210,28 @@ impl Handler<NewThreadPage> for Renderer { } } +/// Message used to render post editing page. +pub struct EditPostPage { + pub id: i32, + pub post: String, +} +message!(EditPostPage, Result<String>); + +impl Handler<EditPostPage> for Renderer { + type Result = Result<String>; + + fn handle(&mut self, msg: EditPostPage, _: &mut Self::Context) -> Self::Result { + let ctx = FormContext { + mode: EditingMode::EditPost, + id: Some(msg.id), + post: Some(msg.post), + ..Default::default() + }; + + Ok(self.tera.render("post.html", &ctx)?) + } +} + /// Message used to render search results #[derive(Serialize)] pub struct SearchResultPage { diff --git a/templates/thread.html b/templates/thread.html index 6a89135cd223..826046ce15aa 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -42,7 +42,7 @@ <div class="d-inline-flex flex-row mt-auto ml-auto"> {%- if post.editable %} - <a href="#edit" class="badge badge-light border m-1 p-1">Edit</a> + <a href="/post/{{ post.id }}/edit" class="badge badge-light border m-1 p-1">Edit</a> {% endif -%} <a href="#quote" class="badge badge-light border m-1 p-1">Quote</a> </div> |