From 42c487006c63259d63dfec2b69f555c0b36539cc Mon Sep 17 00:00:00 2001 From: Yohan Boujon Date: Fri, 15 Mar 2024 21:55:03 +0100 Subject: [PATCH] Backend: Sanitarized json parser (quotes, \n, \r...) Added a get_post route. Frontend: Basic article management. --- backend/include/json.hpp | 2 ++ backend/include/utility.hpp | 16 ++++++++++ backend/src/json.cpp | 13 +++++++- backend/src/main.cpp | 30 ++++++++++++++++++- .../lib/components/carousel-vertical.svelte | 10 +++---- frontend/src/lib/css/base.css | 6 +++- frontend/src/lib/css/carousel.css | 9 +++--- .../routes/articles/[slug]/+page.server.js | 10 +++++++ .../src/routes/articles/[slug]/+page.svelte | 5 ++++ 9 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 backend/include/utility.hpp create mode 100644 frontend/src/routes/articles/[slug]/+page.server.js create mode 100644 frontend/src/routes/articles/[slug]/+page.svelte diff --git a/backend/include/json.hpp b/backend/include/json.hpp index df6f4d6..2a428cb 100644 --- a/backend/include/json.hpp +++ b/backend/include/json.hpp @@ -22,6 +22,8 @@ public: private: Data _dataBuffer; Json _buffer; + + void sanitarize(std::string& str); }; } diff --git a/backend/include/utility.hpp b/backend/include/utility.hpp new file mode 100644 index 0000000..4f66cc7 --- /dev/null +++ b/backend/include/utility.hpp @@ -0,0 +1,16 @@ +#ifndef _HEADER_ETHERYOBLOG_UTILITY +#define _HEADER_ETHERYOBLOG_UTILITY + +#include + +inline void str_replace(std::string& str, const std::string& from, const std::string& to) { + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } +} + +#endif //_HEADER_ETHERYOBLOG_UTILITY \ No newline at end of file diff --git a/backend/src/json.cpp b/backend/src/json.cpp index 1dae8ae..9cbf937 100644 --- a/backend/src/json.cpp +++ b/backend/src/json.cpp @@ -1,4 +1,7 @@ #include "json.hpp" +#include "utility.hpp" +#include +#include using namespace Etheryo; @@ -34,12 +37,13 @@ std::string JsonHandler::to_str() std::string str = "["; size_t map_size(0), map_index(0), vec_index(0); - for (const auto& map_data : _buffer) { + for (auto& map_data : _buffer) { vec_index++; str.push_back('{'); map_size = map_data.size(); for (auto it = map_data.begin(); it != map_data.end(); it++) { map_index++; + sanitarize(it->second); str += ("\"" + it->first + "\": \"" + it->second + (map_index >= map_size ? "\"" : "\",")); } map_index = 0; @@ -49,4 +53,11 @@ std::string JsonHandler::to_str() } str.push_back(']'); return str; +} + +void JsonHandler::sanitarize(std::string& str) +{ + str_replace(str, "\"", "\\\""); + str_replace(str, "\r", "\\r"); + str_replace(str, "\n", "\\n"); } \ No newline at end of file diff --git a/backend/src/main.cpp b/backend/src/main.cpp index 7dd1d7d..0a16b72 100644 --- a/backend/src/main.cpp +++ b/backend/src/main.cpp @@ -3,6 +3,7 @@ #include "crow.h" #include +#include "crow/app.h" #include "crow/http_response.h" #include "dotenv.hpp" #include "json.hpp" @@ -10,16 +11,19 @@ pqxx::connection* globalConnection(nullptr); crow::response test(void); crow::response getSimplePosts(int limit); +crow::response getPost(std::string slug); // Json Handler with a precise data type Etheryo::JsonHandler category; Etheryo::JsonHandler post_info; +Etheryo::JsonHandler post; int main() { // Init Json Objects category.add({ "id", "slug", "icon", "type_icon" }); post_info.add({"slug","author","title", "date", "picture"}); + post.add({"name","title","date","picture","body","views","likes","dislikes"}); // Init Postgresql + DotEnv Etheryo::DotEnv dotenvParser; @@ -31,7 +35,7 @@ int main() crow::SimpleApp app; CROW_ROUTE(app, "/")(test); CROW_ROUTE(app, "/get_simple_posts/")(getSimplePosts); - + CROW_ROUTE(app, "/get_post/")(getPost); app.port(8000).multithreaded().run(); globalConnection->close(); } @@ -72,4 +76,28 @@ crow::response getSimplePosts(int limit) response.add_header("Access-Control-Allow-Origin", "*"); response.add_header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); return response; +} + +crow::response getPost(std::string slug) +{ + post.clear(); + pqxx::work worker { *globalConnection }; + auto result = worker.query + ("select p.author_id, a.name, p.title, p.date, p.picture, p.body, p.views, p.likes, p.dislikes from post p join authors a on p.author_id = a.id where p.slug = '"+slug+"';"); + for(auto [author_id, name, title, date, picture, body, views, likes, dislikes] : result) + { + post["name"] = name; //"title","date","picture","body","views","likes","dislikes" + post["title"] = title; + post["date"] = date; + post["picture"] = picture; + post["body"] = body; + post["views"] = std::to_string(views); + post["likes"] = std::to_string(likes); + post["dislikes"] = std::to_string(dislikes); + post.push(); + } + auto response = crow::response { "application/json", post.to_str() }; + response.add_header("Access-Control-Allow-Origin", "*"); + response.add_header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + return response; } \ No newline at end of file diff --git a/frontend/src/lib/components/carousel-vertical.svelte b/frontend/src/lib/components/carousel-vertical.svelte index 86b4418..675597a 100644 --- a/frontend/src/lib/components/carousel-vertical.svelte +++ b/frontend/src/lib/components/carousel-vertical.svelte @@ -26,13 +26,13 @@ role="button" tabindex="0" on:click={() => { - redirectTo(`/article/${mainpost.slug}`); + redirectTo(`/articles/${mainpost.slug}`); }} - on:keydown={(event) => handleKeyDown(event, `/article/${mainpost.slug}`)} + on:keydown={(event) => handleKeyDown(event, `/articles/${mainpost.slug}`)} >

{mainpost.title}

-
+
mainpicture
@@ -54,9 +54,9 @@ role="button" tabindex="0" on:click={() => { - redirectTo(`/article/${p.slug}`); + redirectTo(`/articles/${p.slug}`); }} - on:keydown={(event) => handleKeyDown(event, `/article/${p.slug}`)} + on:keydown={(event) => handleKeyDown(event, `/articles/${p.slug}`)} > mainpicture
diff --git a/frontend/src/lib/css/base.css b/frontend/src/lib/css/base.css index 1ac6b72..7f9ba81 100644 --- a/frontend/src/lib/css/base.css +++ b/frontend/src/lib/css/base.css @@ -59,7 +59,7 @@ h1 { height: 100%; } -.h-60 { +.h-70 { height: 60%; } @@ -84,6 +84,10 @@ h1 { padding: 0; } +.margin-bottom { + margin-bottom: 0.5rem; +} + .margin-horizontal-05 { margin-top: 0.5rem; margin-bottom: 0.5rem; diff --git a/frontend/src/lib/css/carousel.css b/frontend/src/lib/css/carousel.css index a96f7d4..6a4902d 100644 --- a/frontend/src/lib/css/carousel.css +++ b/frontend/src/lib/css/carousel.css @@ -34,7 +34,6 @@ width: 90%; height: auto; object-fit: cover; - margin-bottom: 0.5rem; } .carousel-v-minpost-container { @@ -71,11 +70,12 @@ transition: all .1s ease 0s; margin-right: 1rem; margin-left: 1rem; + background-color: var(--color-background); } .carousel-v-minpost img { - min-width: 50%; - max-width: 50%; + min-width: 40%; + max-width: 40%; height: 100%; object-fit: cover; margin: 0; @@ -88,5 +88,6 @@ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; - -webkit-line-clamp: 1; + -webkit-line-clamp: 2; + font-size: 1.4rem; } \ No newline at end of file diff --git a/frontend/src/routes/articles/[slug]/+page.server.js b/frontend/src/routes/articles/[slug]/+page.server.js new file mode 100644 index 0000000..7756fc3 --- /dev/null +++ b/frontend/src/routes/articles/[slug]/+page.server.js @@ -0,0 +1,10 @@ +import { error } from '@sveltejs/kit'; + +export function load({ params }) { + const slug = params.slug; + + return { + status: 0, + slug: slug + }; +} diff --git a/frontend/src/routes/articles/[slug]/+page.svelte b/frontend/src/routes/articles/[slug]/+page.svelte new file mode 100644 index 0000000..8923e53 --- /dev/null +++ b/frontend/src/routes/articles/[slug]/+page.svelte @@ -0,0 +1,5 @@ + + +

{data.slug}

\ No newline at end of file