diff --git a/admin-frontend/src/components/create-article-form.js b/admin-frontend/src/components/create-article-form.js index 792877b9553e9509d8e4de035f891c1eaf413a30..c5ed71d81ef85dac1b3567f015c6fa50c440680c 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 eb81cfd2275209c7df20e2e30defeffe180a3a95..e4cf91679b9ed73c8c0773b96b0a0737a4e044f6 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0acb6cc471be81c110c7f969bec0f0ae89870f40 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 1b77ca7d9268c5c1fc4cc4d3218d884bf294b463..6d1e210272f6f5341dcf919b90e2a5e0a04c202b 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 205600bcf25191f6faa0c856d749bedfed128a6a..3b83cc9cb176d13ad6690363143a9a0391a07eae 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 38f78494459aa062a11cb5f00bf50135d1301873..3d5abc23619db42a21a9ed5055150c0707cf0fc4 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(), })