From 2a2ea206ffb04e87bfdd08b1b3268b38977fb2b2 Mon Sep 17 00:00:00 2001 From: Pierre Jarriges <pierre.jarriges@tutanota.com> Date: Sun, 7 Nov 2021 17:57:47 +0100 Subject: [PATCH] admin panel create update delete articles --- .../src/components/create-article-form.js | 31 ++-- admin-frontend/src/components/root.js | 3 +- .../src/components/update-article-form.js | 145 ++++++++++++++++++ admin-frontend/src/xhr.js | 3 +- src/main.rs | 1 + src/service/articles.rs | 8 +- 6 files changed, 176 insertions(+), 15 deletions(-) diff --git a/admin-frontend/src/components/create-article-form.js b/admin-frontend/src/components/create-article-form.js index 792877b..c5ed71d 100644 --- a/admin-frontend/src/components/create-article-form.js +++ b/admin-frontend/src/components/create-article-form.js @@ -1,12 +1,13 @@ "use strict"; const { images_url } = require("../constants"); -const { fetch_post_article, fetch_article } = require("../xhr"); +const { fetch_post_article, fetch_article, fetch_update_article } = require("../xhr"); class CreateArticleForm { - constructor() { + constructor(params) { + this.params = params || {}; this.state = { - output: { + output: this.params.data || { title: "", subtitle: "", category: "", @@ -259,13 +260,24 @@ class CreateArticleForm { }, onsubmit: e => { e.preventDefault(); - fetch_post_article(this.state.output) + + const __fetch = this.params.data + ? fetch_update_article + : fetch_post_article; + + __fetch(this.state.output) .then(res => { - const id = res.insertedId.$oid; - fetch_article(id).then(article => { - this.state.article_sent = article; - this.refresh(); - }).catch(er => console.log(er)); + const id = res.insertedId ? res.insertedId.$oid : res._id ? res._id.$oid : undefined; + if (!id) { + alert("error") + } else { + fetch_article(id) + .then(article => { + this.state.article_sent = article; + this.refresh(); + }) + .catch(er => console.log(er)); + } }) .catch(err => console.log(err)) }, @@ -296,6 +308,7 @@ class CreateArticleForm { gridColumn: "1 / span 2", height: "300px", }, + value: this.state.output.body, placeholder: "Article body", oninput: this.handle_text_input.bind(this, "body") }, diff --git a/admin-frontend/src/components/root.js b/admin-frontend/src/components/root.js index eb81cfd..e4cf916 100644 --- a/admin-frontend/src/components/root.js +++ b/admin-frontend/src/components/root.js @@ -1,5 +1,6 @@ const CreateArticleForm = require("./create-article-form"); +const UpdateArticleForm = require("./update-article-form"); class RootComponent { constructor() { @@ -18,7 +19,7 @@ class RootComponent { case "create": return new CreateArticleForm().render(); case "update": - return undefined; + return new UpdateArticleForm().render(); default: return undefined; } diff --git a/admin-frontend/src/components/update-article-form.js b/admin-frontend/src/components/update-article-form.js index e69de29..0acb6cc 100644 --- a/admin-frontend/src/components/update-article-form.js +++ b/admin-frontend/src/components/update-article-form.js @@ -0,0 +1,145 @@ +"use strict"; + +const { fetch_article_by_title, fetch_delete_article } = require("../xhr"); +const CreateArticleForm = require("./create-article-form"); + +class UpdateArticleForm { + constructor() { + this.state = { + search_article_title: "", + search_result: {}, + article_to_update: {}, + } + } + + reset() { + this.state = { + search_article_title: "", + search_result: {}, + article_to_update: {}, + }; + + this.refresh(); + } + + handle_search_article() { + fetch_article_by_title(this.state.search_article_title) + .then(res => { + this.state.search_result = res; + this.state.article_to_update = {}; + this.refresh_search_result(); + this.refresh_update_form(); + }) + .catch(err => alert(err)); + } + + handle_select_result() { + this.state.article_to_update = { ...this.state.search_result }; + this.refresh_update_form(); + } + + handle_delete_article() { + fetch_delete_article(this.state.search_result._id.$oid) + .then(res => { + alert(res); + this.reset(); + }) + .catch(err => alert(err)) + } + + render_search() { + return { + tag: "form", + onsubmit: e => { + e.preventDefault(); + this.handle_search_article(); + }, + style_rules: { display: "flex", gap: "10px", width: "100%" }, + contents: [ + { + tag: "input", type: "text", value: this.state.search_article_title, + style_rules: { flex: 1 }, + placeholder: "Search article by title", + oninput: e => this.state.search_article_title = e.target.value, + }, + { + tag: "input", type: "submit", value: "SEARCH" + } + ] + } + } + + refresh_search_result() { + obj2htm.subRender( + this.render_search_result(), + document.getElementById("update-article-form-search-result"), + { mode: "replace" }, + ); + } + + render_search_result() { + const { search_result } = this.state; + return { + tag: "div", + id: "update-article-form-search-result", + style_rules: { + display: "flex", + gap: "10px", + alignItems: "center" + }, + contents: search_result.title ? [ + { tag: "strong", contents: search_result.title }, + { + tag: "button", contents: "SELECT", + onclick: this.handle_select_result.bind(this) + }, + { + tag: "button", contents: "DELETE", + onclick: this.handle_delete_article.bind(this) + } + ] : [] + } + } + + refresh_update_form() { + obj2htm.subRender( + this.render_update_form(), + document.getElementById("update-article-form-container"), + { mode: "replace" }, + ); + } + + render_update_form() { + return { + tag: "div", + id: "update-article-form-container", + contents: this.state.article_to_update._id + ? [new CreateArticleForm({ data: this.state.article_to_update }).render()] + : [] + } + } + + refresh() { + obj2htm.subRender(this.render(), document.getElementById("update-article-multiform"), { mode: "replace" }) + } + + render() { + return { + tag: "div", + id: "update-article-multiform", + style_rules: { + display: "flex", + flexDirection: "column", + gap: "20px", + maxWidth: "800px", + }, + contents: [ + this.render_search(), + this.render_search_result(), + this.render_update_form(), + ] + } + } +} + +module.exports = UpdateArticleForm; \ No newline at end of file diff --git a/admin-frontend/src/xhr.js b/admin-frontend/src/xhr.js index 1b77ca7..6d1e210 100644 --- a/admin-frontend/src/xhr.js +++ b/admin-frontend/src/xhr.js @@ -17,6 +17,7 @@ async function fetch_article_by_title(article_title) { return new Promise((resolve, reject) => { fetch(`/article-by-title/`, { + method: "POST", body: new URLSearchParams(form_data), }).then(async res => { if (res.status >= 400 && res.status < 600) { @@ -90,7 +91,7 @@ async function fetch_update_article(article_data) { async function fetch_delete_article(article_id) { return new Promise((resolve, reject) => { - fetch(`/delete_article/${article_id}`, { + fetch(`/delete-article/${article_id}`, { credentials: 'include', method: "DELETE" }) diff --git a/src/main.rs b/src/main.rs index 205600b..3b83cc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,6 +88,7 @@ async fn main() -> std::io::Result<()> { .service(delete_article) .service(get_articles_by_category) .service(get_article) + .service(get_article_by_title) ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // STANDARD FILES /////////////////////////////////////////////////////////////////////////////////////////// .service(resource("/favicon.ico").route(get().to(favicon))) diff --git a/src/service/articles.rs b/src/service/articles.rs index 38f7849..3d5abc2 100644 --- a/src/service/articles.rs +++ b/src/service/articles.rs @@ -102,8 +102,8 @@ pub async fn delete_article( .find_one_and_delete(doc! {"_id": &article_id}, None) .await { - Ok(_) => HttpResponse::Accepted().finish(), - Err(_) => HttpResponse::InternalServerError().finish(), + Ok(_) => HttpResponse::Accepted().body("Article was deleted"), + Err(e) => HttpResponse::InternalServerError().body(&format!("{:?}", e)), } } @@ -157,7 +157,7 @@ pub async fn get_article(app_state: Data<AppState>, article_id: Path<String>) -> } } -#[get("/article-by-title")] +#[post("/article-by-title")] pub async fn get_article_by_title( app_state: Data<AppState>, form_data: Form<ArticleTitleFormData>, @@ -555,7 +555,7 @@ mod test_articles { let req = test::TestRequest::with_uri("/article-by-title") .header("Accept", "application/json") - .method(Method::GET) + .method(Method::POST) .set_form(&ArticleTitleFormData { title: article_title.to_owned(), }) -- GitLab