Commit f492f9e2c3b89302e7f0882e0cc7bd939d6e9b03

Authored by Georg Hopp
1 parent c179a4f8

Add crate for common types and code

  1 +# This is from the webpage:
  2 +# https://www.developer.com/languages/creating-an-api-with-rust-and-sqlite/
  3 +# I have fixed some things manually as the code on that page did not compile
  4 +# without.
  5 +
  6 +# Additional informations at https://actix.rs/docs/databases/ assume one
  7 +# should use web::block to access the database...
  8 +# TODO check what is the difference to this approach.
  9 +# - well, we use web::block already for write actions.
  10 +
  11 +# Introduction to rust async:
  12 +# https://gruberbastian.com/posts/rust_async/
  13 +# https://blog.logrocket.com/a-practical-guide-to-async-in-rust/
  14 +# https://os.phil-opp.com/async-await/
  15 +
  16 +# Simple explanation on technical terms synchronous, asynchronous, concurrent
  17 +# and parallel.
  18 +# https://medium.com/plain-and-simple/synchronous-vs-asynchronous-vs-concurrent-vs-parallel-4342bfb8b9f2
  19 +
  20 +[package]
  21 +name = "artshop-common"
  22 +version = "0.1.0"
  23 +workspace = ".."
  24 +edition = "2018"
  25 +
  26 +[dependencies]
  27 +serde = "^1.0"
... ...
  1 +pub mod types;
... ...
  1 +use serde::{Deserialize, Serialize};
  2 +
  3 +#[derive(Debug, Clone, Deserialize, Serialize)]
  4 +pub enum Either<L, R> {
  5 + Left(L),
  6 + Reight(R)
  7 +}
  8 +
  9 +#[derive(Clone, Debug, Serialize, Deserialize)]
  10 +pub struct MarkdownJson {
  11 + pub name: String,
  12 + pub content: String,
  13 + pub number_of_versions: i32,
  14 + pub date_created: String,
  15 + pub date_updated: String,
  16 +}
... ...
... ... @@ -27,6 +27,7 @@ edition = "2018"
27 27 actix-files = "0.2"
28 28 actix-web = "2.0"
29 29 actix-rt = "1.1.1"
  30 +artshop-common = { path = "../common" }
30 31 diesel = { version = "1.4.7", features = ["sqlite", "r2d2"]}
31 32 r2d2 = "0.8.9"
32 33 dotenv = "0.15.0"
... ...
... ... @@ -2,6 +2,7 @@ use std::sync::Arc;
2 2 use crate::schema::*;
3 3 use crate::error::Error;
4 4 use crate::Pool;
  5 +use artshop_common::types::MarkdownJson;
5 6 use diesel::prelude::*;
6 7 use diesel::{
7 8 dsl::{delete, insert_into, update},
... ... @@ -14,7 +15,7 @@ use flate2::Compression;
14 15 use flate2::write::{DeflateEncoder, DeflateDecoder};
15 16
16 17
17   -#[derive(Debug, Serialize, Deserialize, Queryable, Identifiable)]
  18 +#[derive(Debug, Clone, Serialize, Deserialize, Queryable, Identifiable)]
18 19 pub struct Markdown {
19 20 pub id: i32,
20 21 pub name: String,
... ... @@ -55,12 +56,23 @@ pub struct MarkdownDiffNew<'a> {
55 56
56 57 #[derive(Debug, Serialize, Deserialize, AsChangeset)]
57 58 #[table_name="markdowns"]
58   -pub struct MarkdownJson {
59   - pub name: String,
60   - pub content: String,
  59 +struct MarkdownChange<'a> {
  60 + pub name: &'a str,
  61 + pub content: &'a str,
61 62 pub number_of_versions: i32,
62   - pub date_created: String,
63   - pub date_updated: String,
  63 + pub date_created: &'a str,
  64 + pub date_updated: &'a str,
  65 +}
  66 +
  67 +impl<'a> From<&'a MarkdownJson> for MarkdownChange<'a> {
  68 + fn from(md: &'a MarkdownJson) -> Self {
  69 + Self { name: md.name.as_str()
  70 + , content: md.content.as_str()
  71 + , number_of_versions: md.number_of_versions
  72 + , date_created: md.date_created.as_str()
  73 + , date_updated: md.date_updated.as_str()
  74 + }
  75 + }
64 76 }
65 77
66 78 pub(crate) enum Action {
... ... @@ -108,7 +120,7 @@ pub(crate) fn get_markdowns(pool: Arc<Pool>) -> Result<Vec<Markdown>, Error>
108 120
109 121 pub(crate) fn get_markdown( pool: Arc<Pool>
110 122 , ident: &str
111   - , patch: Option<i32> ) -> Result<Markdown, Error>
  123 + , patch: Option<i32> ) -> Result<Vec<Markdown>, Error>
112 124 {
113 125 use crate::schema::markdowns::dsl::*;
114 126 use crate::schema::markdown_diffs::dsl::*;
... ... @@ -118,6 +130,8 @@ pub(crate) fn get_markdown( pool: Arc<Pool>
118 130 . filter(name.eq(ident))
119 131 . first::<Markdown>(&db_connection)?;
120 132
  133 + let mut mds = vec![markdown.clone()];
  134 +
121 135 if let Some(patch) = patch {
122 136 let result = markdown_diffs . filter(markdown_id.eq(markdown.id))
123 137 . filter(diff_id.ge(patch))
... ... @@ -130,11 +144,13 @@ pub(crate) fn get_markdown( pool: Arc<Pool>
130 144 let decomp = decoder.reset(Vec::new()).unwrap();
131 145 let decomp = Patch::from_str(
132 146 std::str::from_utf8(decomp.as_ref()).unwrap()).unwrap();
133   - markdown.content = apply(&mut markdown.content, &decomp).unwrap();
  147 + markdown.content = apply(&markdown.content, &decomp).unwrap();
  148 + markdown.date_updated = patch.date_created;
  149 + mds.push(markdown.clone());
134 150 }
135 151 };
136 152
137   - Ok(markdown)
  153 + Ok(mds)
138 154 }
139 155
140 156 pub(crate) fn delete_markdown( pool: Arc<Pool>
... ... @@ -185,7 +201,7 @@ pub(crate) fn update_markdown( pool: Arc<Pool>
185 201 insert_into(markdown_diffs) . values(&new_markdown_diff)
186 202 . execute(&db_connection)?;
187 203
188   - update(&markdown).set(&item).execute(&db_connection)?;
  204 + update(&markdown).set(MarkdownChange::from(&item)).execute(&db_connection)?;
189 205
190 206 Ok(())
191 207 }).unwrap();
... ...
... ... @@ -3,6 +3,7 @@ use crate::Pool;
3 3
4 4 use actix_web::{Error, HttpResponse, web};
5 5 use anyhow::Result;
  6 +use artshop_common::types::MarkdownJson;
6 7 use serde::Deserialize;
7 8
8 9 #[derive(Debug, Deserialize)]
... ... @@ -38,7 +39,7 @@ pub async fn get_markdown( pool: web::Data<Pool>
38 39
39 40 pub async fn update_markdown( pool: web::Data<Pool>
40 41 , name: web::Path<String>
41   - , item: web::Json<markdown::MarkdownJson> )
  42 + , item: web::Json<MarkdownJson> )
42 43 -> Result<HttpResponse, Error>
43 44 {
44 45 let pool = pool.into_inner();
... ...
... ... @@ -12,6 +12,7 @@ crate-type = ["cdylib", "rlib"]
12 12 default = ["console_error_panic_hook"]
13 13
14 14 [dependencies]
  15 +artshop-common = { path = "../common" }
15 16 katex = { version = "0.4", default-features = false, features = ["wasm-js"] }
16 17 pulldown-cmark = "0.9"
17 18 console_log = "^0.1"
... ...
1 1 mod data;
2 2
  3 +use artshop_common::types::MarkdownJson;
3 4 use js_sys::JsString;
4 5 use log::Level;
5 6 use mogwai::prelude::*;
... ... @@ -25,22 +26,13 @@ fn md_to_html(source: &str) -> String {
25 26 html_output
26 27 }
27 28
28   -#[derive(Clone, Debug, Serialize, Deserialize)]
29   -pub struct MarkdownJson {
30   - pub name: String,
31   - pub content: String,
32   - pub number_of_versions: i32,
33   - pub date_created: String,
34   - pub date_updated: String,
35   -}
36   -
37   -async fn md_from_db() -> MarkdownJson {
  29 +async fn md_from_db() -> Vec<MarkdownJson> {
38 30 let window = web_sys::window().unwrap();
39 31 let mut opts = RequestInit::new();
40 32 opts.method("GET").mode(RequestMode::Cors);
41 33
42 34 let request = Request::new_with_str_and_init(
43   - "/api/v0/markdowns/md-example?patch=3"
  35 + "/api/v0/markdowns/md-example?patch=1" // patch=1 always gets all patches.
44 36 , &opts ).unwrap();
45 37 request.headers().set("Accept", "application/json").unwrap();
46 38
... ... @@ -51,9 +43,9 @@ async fn md_from_db() -> MarkdownJson {
51 43 . await.unwrap()
52 44 . dyn_into::<JsString>().unwrap()
53 45 );
54   - let data :MarkdownJson = serde_json::from_str(data.as_str()).unwrap();
  46 + let data :Vec<MarkdownJson> = serde_json::from_str(data.as_str()).unwrap();
55 47
56   - data.clone()
  48 + data
57 49 }
58 50
59 51 async fn md_to_db(md :MarkdownJson) {
... ... @@ -80,7 +72,7 @@ async fn md_to_db(md :MarkdownJson) {
80 72 async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
81 73 , tx_view: broadcast::Sender<String>
82 74 , mut rx_dom: broadcast::Receiver<Dom>
83   - , md :MarkdownJson ) {
  75 + , md :Vec<MarkdownJson> ) {
84 76 let dom = rx_dom.next().await.unwrap();
85 77 let mut show_edit = false;
86 78
... ... @@ -98,11 +90,11 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
98 90 fn update(dom: &Dom) {
99 91 if let Either::Left(dom_js) = dom.inner_read() {
100 92 dom_js . to_owned()
101   - . dyn_into::<Node>().unwrap()
102   - . child_nodes().get(1).unwrap()
103   - . child_nodes().get(1).unwrap()
104   - . dyn_into::<HtmlElement>().unwrap()
105   - . set_inner_html(md_to_html(get_md(dom).as_str()).as_str())
  93 + . dyn_into::<Node>().unwrap()
  94 + . child_nodes().get(1).unwrap()
  95 + . child_nodes().get(1).unwrap()
  96 + . dyn_into::<HtmlElement>().unwrap()
  97 + . set_inner_html(md_to_html(get_md(dom).as_str()).as_str())
106 98 };
107 99 }
108 100
... ... @@ -137,7 +129,7 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
137 129 while let Some(msg) = rx_logic.next().await {
138 130 match msg {
139 131 AppLogic::Store => {
140   - let mut new_md = md.clone();
  132 + let mut new_md = md[0].clone();
141 133 new_md.content = get_md(&dom);
142 134 md_to_db(new_md).await;
143 135 },
... ... @@ -158,7 +150,7 @@ async fn editor_logic( mut rx_logic: broadcast::Receiver<AppLogic>
158 150 fn editor_view( tx_logic: broadcast::Sender<AppLogic>
159 151 , rx_view: broadcast::Receiver<String>
160 152 , tx_dom: broadcast::Sender<Dom>
161   - , md: &MarkdownJson
  153 + , md: &Vec<MarkdownJson>
162 154 ) -> ViewBuilder<Dom> {
163 155 let ns = "http://www.w3.org/2000/svg";
164 156
... ... @@ -190,22 +182,151 @@ fn editor_view( tx_logic: broadcast::Sender<AppLogic>
190 182 <div contenteditable="true"
191 183 style:cursor="text"
192 184 style:display=("none", rx_view)>
193   - <pre on:click=store_filter>{md.content.clone()}</pre>
  185 + <pre on:click=store_filter>{md[0].content.clone()}</pre>
194 186 </div>
195 187 <div>
  188 + <div>
  189 + <button>
  190 + <svg xmlns=ns viewBox="0 -1 24 24"
  191 + style:width="1.5em" style:height="1.5em"
  192 + style:fill="none">
  193 + <path xmlns=ns
  194 + style:fill="black"
  195 + d="M9.17154 11.508
  196 + L7.75732 10.0938
  197 + L12 5.85113
  198 + L16.2426 10.0938
  199 + L14.8284 11.508
  200 + L12 8.67956
  201 + L9.17154 11.508Z"/>
  202 + <path xmlns=ns
  203 + style:fill="black"
  204 + d="M9.17154 12.492
  205 + L7.75732 13.9062
  206 + L12 18.1489
  207 + L16.2426 13.9062
  208 + L14.8284 12.492
  209 + L12 15.3204
  210 + L9.17154 12.492Z"/>
  211 + <path xmlns=ns
  212 + style:fill="black"
  213 + style:fill_rule="evenodd"
  214 + style:clip_rule="evenodd"
  215 + d="M1 5
  216 + C1 2.79086 2.79086 1 5 1
  217 + H19
  218 + C21.2091 1 23 2.79086 23 5
  219 + V19
  220 + C23 21.2091 21.2091 23 19 23
  221 + H5
  222 + C2.79086 23 1 21.2091 1 19
  223 + V5Z
  224 + M5 3
  225 + H19
  226 + C20.1046 3 21 3.89543 21 5
  227 + V19
  228 + C21 20.1046 20.1046 21 19 21
  229 + H5
  230 + C3.89543 21 3 20.1046 3 19
  231 + V5
  232 + C3 3.89543 3.89543 3 5 3Z"/>
  233 + </svg>
  234 + </button>
  235 + <button>
  236 + <svg xmlns=ns viewBox="0 -1 32 32"
  237 + style:width="1.5em" style:height="1.5em"
  238 + style:enable_background="new 0 0 32 32"
  239 + style:fill="none"
  240 + style:stroke="#000"
  241 + style:stroke_width="2"
  242 + style:stroke_linecap="round"
  243 + style:stroke_linejoin="round"
  244 + style:stroke_miterlimit="10">
  245 + <ellipse xmlns=ns
  246 + cx="14" cy="8" rx="10" ry="5"/>
  247 + <line xmlns=ns
  248 + x1="24" y1="16" x2="24" y2="8"/>
  249 + <path xmlns=ns
  250 + d="M4,8 v8 c0,2.8,4.5,5,10,5
  251 + c1.2,0,2.3-0.1,3.4-0.3"/>
  252 + <path xmlns=ns
  253 + d="M4,16 v8 c0,2.8,4.5,5,10,5
  254 + c2,0,3.8-0.3,5.3-0.8"/>
  255 + <circle xmlns=ns
  256 + cx="24" cy="23" r="7"/>
  257 + <line xmlns=ns
  258 + x1="24" y1="16" x2="24" y2="26"/>
  259 + <polyline xmlns=ns
  260 + points="21,23 24,26 27,23"/>
  261 + </svg>
  262 + </button>
  263 + <button>
  264 + <svg xmlns=ns viewBox="10.3 3.8 76.2 88.7"
  265 + style:width="1.5em" style:height="1.5em">
  266 + <g xmlns=ns id="_x37_0">
  267 + <polygon xmlns=ns
  268 + points="35.4,18.1 31.1,4.3 31.1,16.3
  269 + 24.5,16.3 24.5,10.9 18.3,18.9
  270 + 13.8,23.7 17,23.7 19.8,31.8
  271 + 27.9,34.1 27.9,37.8 38.7,41.8
  272 + 38.7,34.1 38.7,30.4 38.7,25.2
  273 + 46.8,25.2 "/>
  274 + <path xmlns=ns
  275 + d="M75.7,39.9 h-8.3 h-40.5 h-8.3 h-3 v9.5
  276 + v2 h4.7 c2.2,13.3,6.8,42.2,6.8,42.2 h40
  277 + c0,0,4.6-27.6,7-42.2 h4.7 v-2 v-9.5
  278 + H75.7z
  279 + M67.7,51.4 l-2.6,15.6 l-6.1-6.9 l8-8.7
  280 + H67.7z
  281 + M63.7,75.6 l-1.3,7.9 l-2.9-3.2
  282 + L63.7,75.6z
  283 + M56.6,77.2
  284 + L50,70 l6.2-6.7 l6.4,7.3
  285 + L56.6,77.2z
  286 + M52.4,51.4 h8.9 l-5.1,5.5 l-4.8-5.4
  287 + C51.8,51.4,52.1,51.4,52.4,51.4z
  288 + M53.3,60 l-6.2,6.8 l-6.6-7.2 l6.4-6.9
  289 + L53.3,60z
  290 + M30.5,74.9 l4.6,5 l-3.2,3.5
  291 + L30.5,74.9z
  292 + M31.4,69.6 l6.2-6.8 l6.6,7.2 l-6.2,6.8
  293 + L31.4,69.6z
  294 + M41.9,51.4 c0.1,0,0.2,0,0.3,0 l-4.7,5.1
  295 + l-4.7-5.1
  296 + H41.9z
  297 + M27.1,51.4 l7.6,8.3 l-5.7,6.2l-2.3-14.5
  298 + H27.1z
  299 + M34.6,86.7 l3.3-3.6 l3.3,3.6
  300 + H34.6z
  301 + M47.1,86.7 l-6.2-6.8 l6.2-6.8 l6.6,7.2
  302 + l-5.8,6.4
  303 + H47.1z
  304 + M53.7,86.7 l2.9-3.2 l3,3.2
  305 + H53.7z"/>
  306 + </g>
  307 + </svg>
  308 + </button>
196 309 <button on:click=toggle_filter>
197   - <svg version="1.1" id="Capa_1" xmlns=ns
198   - x="0px" y="0px" viewBox="0 0 220.001 220.001"
  310 + <svg xmlns=ns viewBox="0 0 220.001 220.001"
199 311 style:width="1.5em" style:height="1.5em">
200 312 <g xmlns=ns>
201   - <polygon xmlns=ns points="0,220 59.34,213.86 6.143,160.661"></polygon>
202   - <path xmlns=ns d="M132.018,34.787l53.197,53.197L69.568,203.631L16.37,
203   - 150.434L132.018,34.787z M212.696,60.502c9.738-9.738,9.742-25.527,
204   - 0-35.268l-17.93-17.93c-9.738-9.74-25.529-9.738-35.268,0l-17.346,
205   - 17.347l53.199,53.196L212.696,60.502z"></path>
  313 + <polygon xmlns=ns
  314 + points="0,220 59.34,213.86 6.143,160.661"/>
  315 + <path xmlns=ns
  316 + d="M132.018,34.787 l53.197,53.197
  317 + L69.568,203.631
  318 + L16.37,150.434
  319 + L132.018,34.787z
  320 + M212.696,60.502
  321 + c9.738,-9.738,9.742,-25.527,0,-35.268
  322 + l-17.93,-17.93
  323 + c-9.738,-9.74,-25.529,-9.738,-35.268,0
  324 + l-17.346,17.347 l53.199,53.196
  325 + L212.696,60.502z"/>
206 326 </g>
207 327 </svg>
208 328 </button>
  329 + </div>
209 330 <div></div>
210 331 <div></div>
211 332 <div></div>
... ...
Please register or login to post a comment