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").
This commit is contained in:
parent
7a55786552
commit
705097dab9
5 changed files with 63 additions and 2 deletions
|
@ -54,6 +54,9 @@ pub enum ConverseError {
|
||||||
#[fail(display = "error occured running timer: {}", error)]
|
#[fail(display = "error occured running timer: {}", error)]
|
||||||
Timer { error: tokio_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
|
// This variant is used as a catch-all for wrapping
|
||||||
// actix-web-compatible response errors, such as the errors it
|
// actix-web-compatible response errors, such as the errors it
|
||||||
// throws itself.
|
// throws itself.
|
||||||
|
|
|
@ -189,6 +189,41 @@ pub fn reply_thread(state: State<AppState>,
|
||||||
.responder()
|
.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
|
/// This handler executes a full-text search on the forum database and
|
||||||
/// displays the results to the user.
|
/// displays the results to the user.
|
||||||
pub fn search_forum(state: State<AppState>,
|
pub fn search_forum(state: State<AppState>,
|
||||||
|
|
|
@ -181,6 +181,7 @@ fn start_http_server(base_url: String,
|
||||||
.resource("/thread/submit", |r| r.method(Method::POST).with3(submit_thread))
|
.resource("/thread/submit", |r| r.method(Method::POST).with3(submit_thread))
|
||||||
.resource("/thread/reply", |r| r.method(Method::POST).with3(reply_thread))
|
.resource("/thread/reply", |r| r.method(Method::POST).with3(reply_thread))
|
||||||
.resource("/thread/{id}", |r| r.method(Method::GET).with3(forum_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("/search", |r| r.method(Method::GET).with2(search_forum))
|
||||||
.resource("/oidc/login", |r| r.method(Method::GET).with(login))
|
.resource("/oidc/login", |r| r.method(Method::GET).with(login))
|
||||||
.resource("/oidc/callback", |r| r.method(Method::POST).with3(callback));
|
.resource("/oidc/callback", |r| r.method(Method::POST).with3(callback));
|
||||||
|
|
|
@ -200,7 +200,7 @@ impl Handler<NewThreadPage> for Renderer {
|
||||||
type Result = Result<String>;
|
type Result = Result<String>;
|
||||||
|
|
||||||
fn handle(&mut self, msg: NewThreadPage, _: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: NewThreadPage, _: &mut Self::Context) -> Self::Result {
|
||||||
let ctx: FormContext = FormContext {
|
let ctx = FormContext {
|
||||||
alerts: msg.alerts,
|
alerts: msg.alerts,
|
||||||
title: msg.title,
|
title: msg.title,
|
||||||
post: msg.post,
|
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
|
/// Message used to render search results
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct SearchResultPage {
|
pub struct SearchResultPage {
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
<div class="d-inline-flex flex-row mt-auto ml-auto">
|
<div class="d-inline-flex flex-row mt-auto ml-auto">
|
||||||
{%- if post.editable %}
|
{%- 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 -%}
|
{% endif -%}
|
||||||
<a href="#quote" class="badge badge-light border m-1 p-1">Quote</a>
|
<a href="#quote" class="badge badge-light border m-1 p-1">Quote</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue