diff options
-rw-r--r-- | src/db.rs | 4 | ||||
-rw-r--r-- | src/handlers.rs | 14 | ||||
-rw-r--r-- | src/render.rs | 49 | ||||
-rw-r--r-- | templates/new-thread.html | 56 | ||||
-rw-r--r-- | templates/post.html | 103 | ||||
-rw-r--r-- | templates/thread.html | 2 |
6 files changed, 156 insertions, 72 deletions
diff --git a/src/db.rs b/src/db.rs index 22438d2b8766..ad1c148a7072 100644 --- a/src/db.rs +++ b/src/db.rs @@ -80,7 +80,7 @@ impl Handler<GetThread> for DbExecutor { /// Message used to create a new thread pub struct CreateThread { pub new_thread: NewThread, - pub body: String, + pub post: String, } impl Message for CreateThread { @@ -105,7 +105,7 @@ impl Handler<CreateThread> for DbExecutor { // ... then create the first post in the thread. let new_post = NewPost { thread_id: thread.id, - body: msg.body, + body: msg.post, author_name: msg.new_thread.author_name.clone(), author_email: msg.new_thread.author_email.clone(), }; diff --git a/src/handlers.rs b/src/handlers.rs index 1cd596aad1d2..8bfd3c1511e6 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -99,7 +99,7 @@ fn anonymous() -> Author { #[derive(Deserialize)] pub struct NewThreadForm { pub title: String, - pub body: String, + pub post: String, } const NEW_THREAD_LENGTH_ERR: &'static str = "Title and body can not be empty!"; @@ -112,16 +112,16 @@ pub fn submit_thread(state: State<AppState>, // Trim whitespace out of inputs: let input = NewThreadForm { title: input.title.trim().into(), - body: input.body.trim().into(), + post: input.post.trim().into(), }; // Perform simple validation and abort here if it fails: - if input.title.is_empty() || input.body.is_empty() { + if input.title.is_empty() || input.post.is_empty() { return state.renderer .send(NewThreadPage { alerts: vec![NEW_THREAD_LENGTH_ERR], title: Some(input.title), - body: Some(input.body), + post: Some(input.post), }) .flatten() .map(|res| HttpResponse::Ok().content_type(HTML).body(res)) @@ -140,7 +140,7 @@ pub fn submit_thread(state: State<AppState>, let msg = CreateThread { new_thread, - body: input.body, + post: input.post, }; state.db.send(msg) @@ -158,7 +158,7 @@ pub fn submit_thread(state: State<AppState>, #[derive(Deserialize)] pub struct NewPostForm { pub thread_id: i32, - pub body: String, + pub post: String, } /// This handler receives a "Reply"-form and redirects the user to the @@ -172,7 +172,7 @@ pub fn reply_thread(state: State<AppState>, let new_post = NewPost { thread_id: input.thread_id, - body: input.body.trim().into(), + body: input.post.trim().into(), author_name: author.name, author_email: author.email, }; diff --git a/src/render.rs b/src/render.rs index 9cc9efd4d10e..d95fb693478b 100644 --- a/src/render.rs +++ b/src/render.rs @@ -159,6 +159,41 @@ impl Handler<ThreadPage> for Renderer { } } +/// The different types of editing modes supported by the editing +/// template: +#[derive(Debug, Serialize)] +pub enum EditingMode { + NewThread, + PostReply, + EditPost, +} + +impl Default for EditingMode { + fn default() -> EditingMode { EditingMode::NewThread } +} + +/// This struct represents the context submitted to the template used +/// for rendering the new thread, edit post and reply to thread forms. +#[derive(Default, Serialize)] +pub struct FormContext { + /// Which editing mode is to be used by the template? + pub mode: EditingMode, + + /// Potential alerts to display to the user (e.g. input validation + /// results) + pub alerts: Vec<&'static str>, + + /// Either the title to be used in the subject field or the title + /// of the thread the user is responding to. + pub title: Option<String>, + + /// Body of the post being edited, if present. + pub post: Option<String>, + + /// ID of the thread being replied to or the post being edited. + pub id: Option<i32>, +} + /// Message used to render new thread page. /// /// It can optionally contain a vector of warnings to display to the @@ -167,7 +202,7 @@ impl Handler<ThreadPage> for Renderer { pub struct NewThreadPage { pub alerts: Vec<&'static str>, pub title: Option<String>, - pub body: Option<String>, + pub post: Option<String>, } impl Message for NewThreadPage { @@ -178,11 +213,13 @@ impl Handler<NewThreadPage> for Renderer { type Result = Result<String>; fn handle(&mut self, msg: NewThreadPage, _: &mut Self::Context) -> Self::Result { - let mut ctx = Context::new(); - ctx.add("alerts", &msg.alerts); - ctx.add("title", &msg.title.map(|s| escape_html(&s))); - ctx.add("body", &msg.body.map(|s| escape_html(&s))); - Ok(self.tera.render("new-thread.html", &ctx)?) + let ctx: FormContext = FormContext { + alerts: msg.alerts, + title: msg.title, + post: msg.post, + ..Default::default() + }; + Ok(self.tera.render("post.html", &ctx)?) } } diff --git a/templates/new-thread.html b/templates/new-thread.html deleted file mode 100644 index 855626b8e423..000000000000 --- a/templates/new-thread.html +++ /dev/null @@ -1,56 +0,0 @@ -<!doctype html> -<html lang="en"> - <head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <meta http-equiv="Content-Security-Policy" content="script-src 'self';"> - <!-- Bootstrap CSS --> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> - <title>Converse Index</title> - </head> - <body> - <header> - <nav class="navbar navbar-light bg-light justify-content-between mb-3"> - <a class="navbar-brand" href="/"> - <h2>Converse: New Thread</h2> - </a> - <form class="form-inline"> - <a class="btn btn-outline-secondary my-2" href="/">Back to index</a> - </form> - </nav> - </header> - <div class="container border rounded"> - <div class="col-8"> - {% for alert in alerts %} - <div class="alert alert-warning m-3"><strong>{{ alert }}</strong></div> - {% endfor %} - <p class="mt-3">Make <i>your own thread</i> on these here forums!</p> - <p>Remember that you can use <strong>Markdown</strong> when - writing your posts.</p> - <form action="/thread/submit" method="post"> - <div class="row"> - <div class="col-8 input-group m-3"> - <div class="input-group-prepend"> - <span class="input-group-text" id="title-text">Title:</span> - </div> - <input type="text" class="form-control" id="title" name="title" aria-describedby="title-text" {% if title %}value="{{ title }}"{% endif %}> - </div> - </div> - <div class="row"> - <div class="col-8 input-group m-3"> - <div class="input-group-prepend"> - <span class="input-group-text" id="body-text">Body:</span> - </div> - <textarea class="form-control" id="body" name="body" aria-label="thread body">{%if body %}{{ body }}{% endif %}</textarea> - </div> - </div> - <div class="row"> - <div class="col-2 m-3"> - <button class="btn btn-outline-primary" type="submit">Post!</button> - </div> - </div> - </form> - </div> - </div> - </body> -</html> diff --git a/templates/post.html b/templates/post.html new file mode 100644 index 000000000000..74cf03abf307 --- /dev/null +++ b/templates/post.html @@ -0,0 +1,103 @@ +<!-- {# + This template is shared by the new thread, reply and post-editing pages. + + The main display differences between the different editing styles are the + headline of the page ("Submit new thread", "Reply to thread", "Edit post") + and whether or not the subject line field is displayed in the input form. + + Every one of these pages can have a variable length list of alerts submitted + into the template, which will be rendered as Boostrap alert boxes above the + user input form. +#} --> + +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta http-equiv="Content-Security-Policy" content="script-src 'self';"> + <!-- Bootstrap CSS --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> + <title>Converse Index</title> + </head> + <body> + <header> + <nav class="navbar navbar-light bg-light justify-content-between mb-3"> + <a class="navbar-brand" href="/"> + {% if mode == "NewThread" %} + <h2>Converse: Submit new thread</h2> + {% elif mode == "PostReply" %} + <h2>Converse: Reply to thread</h2> + {% elif mode == "EditPost" %} + <h2>Converse: Edit post</h2> + {% endif %} + </a> + <form class="form-inline"> + <a class="btn btn-outline-secondary my-2" href="/">Back to index</a> + </form> + </nav> + </header> + <div class="container border rounded"> + <div class="d-flex flex-column mt-3 border-bottom"> + {%- for alert in alerts %} + <div class="alert alert-warning m-3"><strong>{{ alert }}</strong></div> + {% endfor -%} + + {%- if mode == "NewThread" %} + <h5>Create a new thread</h5> + {% elif mode == "PostReply" %} + <h5>Respond to thread '{{ title }}'</h5> + {% elif mode == "EditPost" %} + <h5>Edit your post</h5> + {% endif -%} + </div> + <div class="d-flex flex-column mt-3"> + {% if mode == "NewThread" %} + <form action="/thread/submit" method="post"> + {% elif mode == "PostReply" %} + <form action="/thread/reply" method="post"> + {% elif mode == "EditPost" %} + <form action="/post/edit" method="post"> + {% endif %} + {% if mode == "PostReply" %} + <input type="hidden" id="thread_id" name="thread_id" value="{{ id }}"> + {% elif mode == "EditPost" %} + <input type="hidden" id="thread_id" name="post_id" value="{{ id }}"> + {% endif %} + + {% if mode == "NewThread" %} + <div class="input-group mb-3"> + <div class="input-group-prepend"> + <span class="input-group-text" id="title-text">Title:</span> + </div> + <input type="text" class="form-control" id="title" name="title" aria-label="thread title" {% if title %}value="{{ title }}"{% endif %}> + </div> + {% endif %} + + <div class="d-flex flex-row"> + <div class="input-group"> + <div class="input-group-prepend"> + <span class="input-group-text" id="post-text">Post:</span> + </div> + <textarea class="form-control" id="post" name="post" rows="15" aria-label="post content">{% if body %}{{ body }}{% endif %}</textarea> + </div> + <div class="d-flex flex-column flex-wrap-reverse border rounded"> + <p class="m-2 pb-2 border-bottom border-dark"> + Remember that you can use <a href="https://daringfireball.net/projects/markdown/basics"><strong>Markdown</strong></a> when + writing your posts: + </p> + <p class="ml-4 m-2"><i>*italic text*</i></p> + <p class="ml-4 m-2"><strong>**bold text**</strong></p> + <p class="ml-4 m-2"><s>~strikethrough text~</s></p> + <p class="ml-4 m-2"><code>[link text](https://some.link.com/)</code></p> + <p class="ml-4 m-2"><code>![image text](https://foo.com/thing.jpg)</code></p> + <p class="ml-4 m-2">Use <code>*</code> or <code>-</code> to enumerate lists.</p> + <p class="ml-4 m-2">See Markdown documentation for more information!</p> + </div> + </div> + <button class="btn btn-primary mt-3 mb-3" type="submit">Post!</button> + </form> + </div> + </div> + </body> +</html> diff --git a/templates/thread.html b/templates/thread.html index f11b96b4d7af..6a89135cd223 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -55,7 +55,7 @@ <input type="hidden" id="thread_id" name="thread_id" value="{{ id }}"> <label for="body">You can use <strong>Markdown</strong>!</label> <div class="input-group"> - <textarea class="form-control" id="body" name="body" aria-label="thread response" rows="10"></textarea> + <textarea class="form-control" id="post" name="post" aria-label="thread response" rows="10"></textarea> <div class="input-group-append"> <button class="btn btn-primary" type="submit">Post!</button> </div> |