diff --git a/admin-frontend/src/components/create-article-form.js b/admin-frontend/src/components/create-article-form.js index 39b06fc3549d6e9122ddcce5e318b33a2fb1a433..792877b9553e9509d8e4de035f891c1eaf413a30 100644 --- a/admin-frontend/src/components/create-article-form.js +++ b/admin-frontend/src/components/create-article-form.js @@ -1,6 +1,7 @@ "use strict"; -const { fetch_post_article } = require("../xhr"); +const { images_url } = require("../constants"); +const { fetch_post_article, fetch_article } = require("../xhr"); class CreateArticleForm { constructor() { @@ -12,10 +13,24 @@ class CreateArticleForm { details: [], images: [], body: "", - } + }, + article_sent: {}, } } + reset() { + this.state.output = { + title: "", + subtitle: "", + category: "", + details: [], + images: [], + body: "", + }; + this.state.article_sent = {}; + this.refresh(); + } + handle_text_input(field, e) { this.state.output[field] = e.target.value; } @@ -128,11 +143,30 @@ class CreateArticleForm { return { tag: "li", style_rules: { - display: "grid", - gridTemplateColumns: "300px 60px", + display: "flex", + alignItems: "center", gap: "10px", }, contents: [ + { + tag: "div", + style_rules: { + display: "flex", + flexDirection: "center", + alignItems: "center", + justifyContent: "center", + width: "150px", + height: "150px", + overflow: "hidden", + }, + contents: [ + { + tag: "img", + style_rules: { minWidth: "100%", minHeight: "100%" }, + src: img ? `${images_url}/${img}` : "", + } + ], + }, { tag: "input", type: "text", @@ -142,6 +176,10 @@ class CreateArticleForm { this.state.output.images[i] = e.target.value; } }, + { + tag: "button", contents: "OK", + onclick: this.refresh_images.bind(this) + }, { tag: "button", contents: "DEL", onclick: this.handle_del_image.bind(this, i) @@ -159,9 +197,60 @@ class CreateArticleForm { } } + render_article_sent() { + const article = this.state.article_sent; + return { + tag: "div", + style_rules: { + maxWidth: "800px", + }, + contents: [ + { tag: "button", contents: "RESET", onclick: this.reset.bind(this) }, + { tag: "h2", contents: article.title }, + { tag: "h4", contents: article.subtitle }, + { tag: "p", contents: article.body.replace(/\n/g, "<br>") }, + { + tag: "ul", contents: article.details.map(det => { + return { + tag: "li", + style_rules: { + display: "flex", + gap: "20px", + justifyContent: "space-between", + }, + contents: [ + { tag: "span", contents: det.label }, + { tag: "span", contents: det.value } + ] + }; + }) + }, + { + tag: "div", style_rules: { display: "flex", gap: "10px" }, + contents: article.images.map(img => { + return { + tag: "img", + style_rules: { height: "100px", width: "auto" }, + src: `${images_url}/${img}` + } + }) + } + ] + } + } + + refresh() { + obj2htm.subRender( + this.render(), + document.getElementById("create-article-form"), + { mode: "replace" } + ); + } + render() { return { tag: "form", + id: "create-article-form", style_rules: { display: "grid", maxWidth: "800px", @@ -170,12 +259,17 @@ class CreateArticleForm { }, onsubmit: e => { e.preventDefault(); - console.log("will post output", this.state.output) - // fetch_post_article(this.state.output) - // .then(res => console.log(res)) - // .catch(err => console.log(err)) + fetch_post_article(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)); + }) + .catch(err => console.log(err)) }, - contents: [ + contents: this.state.article_sent._id ? [this.render_article_sent()] : [ { tag: "input", type: "text", placeholder: "category", value: this.state.output.category, diff --git a/admin-frontend/src/components/root.js b/admin-frontend/src/components/root.js new file mode 100644 index 0000000000000000000000000000000000000000..eb81cfd2275209c7df20e2e30defeffe180a3a95 --- /dev/null +++ b/admin-frontend/src/components/root.js @@ -0,0 +1,53 @@ + +const CreateArticleForm = require("./create-article-form"); + +class RootComponent { + constructor() { + this.state = { + selected_tab: "" + }; + } + + handle_nav_click(e) { + this.state.selected_tab = e.target.tab_name; + obj2htm.renderCycle(); + } + + render_state() { + switch (this.state.selected_tab) { + case "create": + return new CreateArticleForm().render(); + case "update": + return undefined; + default: + return undefined; + } + } + + render() { + return { + tag: "main", + contents: [ + { tag: "h1", contents: "Kuadrado admin panel" }, + { + tag: "nav", + contents: [ + { + tag: "span", contents: "Create article", tab_name: "create", + class: this.state.selected_tab === "create" ? "selected" : "", + onclick: this.handle_nav_click.bind(this), + }, + { + tag: "span", contents: "Update article", tab_name: "update", + class: this.state.selected_tab === "update" ? "selected" : "", + onclick: this.handle_nav_click.bind(this), + }, + ], + }, + this.render_state(), + ], + }; + } +} + +module.exports = RootComponent; \ No newline at end of file diff --git a/admin-frontend/src/components/update-article-form.js b/admin-frontend/src/components/update-article-form.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/admin-frontend/src/constants.js b/admin-frontend/src/constants.js new file mode 100644 index 0000000000000000000000000000000000000000..ffe6ed3440749abe33a335520686fda62d878cf2 --- /dev/null +++ b/admin-frontend/src/constants.js @@ -0,0 +1,3 @@ +module.exports = { + images_url: "/assets/images" +} \ No newline at end of file diff --git a/admin-frontend/src/index.js b/admin-frontend/src/index.js index ee56e9a37c83b03e82a1e69b6e5a5e84ee65af55..7be69ac961e84325f2127c80af1a740d9e9b2abb 100644 --- a/admin-frontend/src/index.js +++ b/admin-frontend/src/index.js @@ -1,60 +1,6 @@ const renderer = require("object-to-html-renderer"); -const CreateArticleForm = require("./components/create-article-form"); - -class RootComponent { - constructor() { - this.state = { - selected_tab: "" - }; - } - - handle_nav_click(e) { - this.state.selected_tab = e.target.tab_name; - this.refresh(); - } - - refresh() { - obj2htm.renderCycle(); - } - - render_state() { - switch (this.state.selected_tab) { - case "create": - return new CreateArticleForm().render(); - case "update": - return undefined; - default: - return undefined; - } - } - - render() { - return { - tag: "main", - contents: [ - { tag: "h1", contents: "Kuadrado admin panel" }, - { - tag: "nav", - contents: [ - { - tag: "span", contents: "Create article", tab_name: "create", - class: this.state.selected_tab === "create" ? "selected" : "", - onclick: this.handle_nav_click.bind(this), - }, - { - tag: "span", contents: "Update article", tab_name: "update", - class: this.state.selected_tab === "update" ? "selected" : "", - onclick: this.handle_nav_click.bind(this), - }, - ], - }, - this.render_state(), - ], - }; - } -} +const RootComponent = require("./components/root"); renderer.register("obj2htm"); - obj2htm.setRenderCycleRoot(new RootComponent()); obj2htm.renderCycle(); \ No newline at end of file diff --git a/admin-frontend/src/xhr.js b/admin-frontend/src/xhr.js index d5321e9e4b666fb84078fd2e66af55c7d5657ca8..1b77ca7d9268c5c1fc4cc4d3218d884bf294b463 100644 --- a/admin-frontend/src/xhr.js +++ b/admin-frontend/src/xhr.js @@ -53,11 +53,12 @@ async function fetch_post_article(article_data) { body: JSON.stringify(article_data), }) .then(async res => { - const text = await res.text(); if (res.status >= 400 && res.status < 600) { + const text = await res.text(); reject(text) } else { - resolve(text); + const json = await res.json(); + resolve(json); } }) .catch(err => reject(err)) @@ -75,11 +76,12 @@ async function fetch_update_article(article_data) { body: JSON.stringify(article_data), }) .then(async res => { - const text = await res.text(); if (res.status >= 400 && res.status < 600) { + const text = await res.text(); reject(text) } else { - resolve(text); + const json = await res.json(); + resolve(json); } }) .catch(err => reject(err)) diff --git a/public/articles/software/object-to-html-renderer/images/obj-to-html-logo.png b/public/articles/software/object-to-html-renderer/images/obj2htm-logo.png similarity index 100% rename from public/articles/software/object-to-html-renderer/images/obj-to-html-logo.png rename to public/articles/software/object-to-html-renderer/images/obj2htm-logo.png diff --git a/public/assets/images/mental-eau.png b/public/assets/images/mental-eau.png new file mode 100644 index 0000000000000000000000000000000000000000..ed6c2eeced7fbb226d7c30e1a526b7c0b09c6d93 Binary files /dev/null and b/public/assets/images/mental-eau.png differ diff --git a/public/assets/images/obj2htm-logo.png b/public/assets/images/obj2htm-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8efda75f697267280b833f5aeb6b1a36b96cee67 Binary files /dev/null and b/public/assets/images/obj2htm-logo.png differ diff --git a/public/assets/images/screen_make_frames.png b/public/assets/images/screen_make_frames.png new file mode 100644 index 0000000000000000000000000000000000000000..1cad3ad3fa68becd61855f7055cfacfc231ef401 Binary files /dev/null and b/public/assets/images/screen_make_frames.png differ diff --git a/src/middleware.rs b/src/middleware.rs index a239355e41c5c75adadd7f8a4fc89aed3c2789b3..1dde054b02d777b3c567627416f2001192bd3e19 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -2,14 +2,15 @@ use crate::{ model::{AdminAuthCredentials, Administrator}, AppState, }; -use actix_web::{http::Cookie, web::Form, HttpMessage, HttpRequest}; +use actix_web::{cookie::SameSite, http::Cookie, web::Form, HttpMessage, HttpRequest}; use wither::{bson::doc, prelude::Model}; -/// Returns a actix_web::http::Cookie instance designed to be an authentication cookie. +/// Returns a Secure actix_web::http::Cookie. pub fn get_auth_cookie(name: &'static str, value: String) -> Cookie<'static> { Cookie::build(name, value) .secure(true) .http_only(true) + .same_site(SameSite::Strict) .path("/") .finish() } diff --git a/src/service/articles.rs b/src/service/articles.rs index fe2cf628364cb2f4243712710b60ef8c67931d43..38f78494459aa062a11cb5f00bf50135d1301873 100644 --- a/src/service/articles.rs +++ b/src/service/articles.rs @@ -40,7 +40,7 @@ pub async fn post_article( .insert_one(article_data, None) .await { - Ok(_) => HttpResponse::Created().body("Article inserted with success"), + Ok(res) => HttpResponse::Created().json(res), Err(e) => { HttpResponse::InternalServerError().body(format!("Error inserting new article {:?}", e)) } @@ -74,7 +74,7 @@ pub async fn update_article( .find_one_and_replace(doc! {"_id": &article_id}, article_data, None) .await { - Ok(_) => HttpResponse::Ok().finish(), + Ok(res) => HttpResponse::Ok().json(res.unwrap()), Err(_) => HttpResponse::InternalServerError().finish(), } }