diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 4ddfdc4..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -blog/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cbd8642..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Dominic Grimm - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/backend/.dockerignore b/backend/.dockerignore index 889a42e..97c2bc9 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -6,4 +6,3 @@ Dockerfile vendor/ example/ static/ -LICENSE diff --git a/backend/Cargo.lock b/backend/Cargo.lock index bdbdcdf..0d8aa51 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -30,7 +30,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64 0.21.0", + "base64", "bitflags", "brotli", "bytes", @@ -43,14 +43,14 @@ dependencies = [ "http", "httparse", "httpdate", - "itoa 1.0.5", + "itoa", "language-tags", "local-channel", "mime", "percent-encoding", "pin-project-lite", "rand", - "sha1 0.10.5", + "sha1", "smallvec", "tokio", "tokio-util", @@ -155,7 +155,7 @@ dependencies = [ "futures-core", "futures-util", "http", - "itoa 1.0.5", + "itoa", "language-tags", "log", "mime", @@ -322,17 +322,6 @@ dependencies = [ "toml", ] -[[package]] -name = "async-trait" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -350,14 +339,13 @@ dependencies = [ "askama_actix", "chrono", "clap", - "comrak", "diesel", "env_logger", "envconfig", "fronma", "lazy_static", "log", - "r2d2_redis", + "pulldown-cmark", "scan_dir", "serde", "serde_yaml 0.9.17", @@ -380,42 +368,12 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bitflags" version = "1.3.2" @@ -533,7 +491,6 @@ dependencies = [ "once_cell", "strsim", "termcolor", - "terminal_size", ] [[package]] @@ -568,38 +525,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "comrak" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784836d0812dade01579cc0cc9b1684847044e716fd7aa6bffbc172e42199500" -dependencies = [ - "clap", - "emojis", - "entities", - "memchr", - "once_cell", - "pest", - "pest_derive", - "regex", - "shell-words", - "slug", - "syntect", - "typed-arena", - "unicode_categories", - "xdg", -] - [[package]] name = "convert_case" version = "0.4.0" @@ -708,12 +633,6 @@ dependencies = [ "syn", ] -[[package]] -name = "deunicode" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" - [[package]] name = "diesel" version = "2.0.3" @@ -724,7 +643,7 @@ dependencies = [ "byteorder", "chrono", "diesel_derives", - "itoa 1.0.5", + "itoa", "pq-sys", "r2d2", ] @@ -751,41 +670,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - -[[package]] -name = "emojis" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fe60b864b6544ad211d4053ced474a9b9d2c8d66b77f01d6c6bcfed10c6bf0" -dependencies = [ - "phf", -] - [[package]] name = "encoding_rs" version = "0.8.32" @@ -795,12 +679,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "entities" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" - [[package]] name = "env_logger" version = "0.10.0" @@ -855,16 +733,6 @@ dependencies = [ "libc", ] -[[package]] -name = "fancy-regex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" -dependencies = [ - "bit-set", - "regex", -] - [[package]] name = "flate2" version = "1.0.25" @@ -1018,7 +886,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.5", + "itoa", ] [[package]] @@ -1111,12 +979,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.5" @@ -1159,15 +1021,6 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - [[package]] name = "link-cplusplus" version = "1.0.8" @@ -1329,28 +1182,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" -[[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "os_str_bytes" version = "6.4.1" @@ -1407,68 +1238,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" -[[package]] -name = "pest" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" -dependencies = [ - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1487,20 +1256,6 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" -[[package]] -name = "plist" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5329b8f106a176ab0dce4aae5da86bfcb139bb74fb00882859e03745011f3635" -dependencies = [ - "base64 0.13.1", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time 0.3.17", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1549,21 +1304,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-xml" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.23" @@ -1584,16 +1341,6 @@ dependencies = [ "scheduled-thread-pool", ] -[[package]] -name = "r2d2_redis" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "182473b876b0b93e353682ec58e207dd1cb4a62278bbe0045fe52b86b74363bb" -dependencies = [ - "r2d2", - "redis", -] - [[package]] name = "rand" version = "0.8.5" @@ -1624,21 +1371,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redis" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f0ceb2ec0dd769483ecd283f6615aa83dcd0be556d5294c6e659caefe7cc54" -dependencies = [ - "async-trait", - "combine", - "dtoa", - "itoa 0.4.8", - "percent-encoding", - "sha1 0.6.1", - "url", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -1648,17 +1380,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - [[package]] name = "regex" version = "1.7.1" @@ -1711,21 +1432,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scan_dir" version = "0.3.3" @@ -1788,7 +1494,7 @@ version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ - "itoa 1.0.5", + "itoa", "ryu", "serde", ] @@ -1800,7 +1506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.5", + "itoa", "ryu", "serde", ] @@ -1824,21 +1530,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567" dependencies = [ "indexmap", - "itoa 1.0.5", + "itoa", "ryu", "serde", "unsafe-libyaml", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.5" @@ -1850,29 +1547,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1882,12 +1556,6 @@ dependencies = [ "libc", ] -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "slab" version = "0.4.7" @@ -1897,15 +1565,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slug" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" -dependencies = [ - "deunicode", -] - [[package]] name = "smallvec" version = "1.10.0" @@ -1950,30 +1609,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syntect" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8" -dependencies = [ - "bincode", - "bitflags", - "fancy-regex", - "flate2", - "fnv", - "lazy_static", - "once_cell", - "onig", - "plist", - "regex-syntax", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "walkdir", - "yaml-rust", -] - [[package]] name = "termcolor" version = "1.2.0" @@ -1983,36 +1618,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal_size" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" -dependencies = [ - "rustix", - "windows-sys 0.42.0", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tikv-jemalloc-sys" version = "0.5.3+5.3.0-patched" @@ -2050,7 +1655,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "itoa 1.0.5", + "itoa", "serde", "time-core", "time-macros", @@ -2148,24 +1753,12 @@ dependencies = [ "once_cell", ] -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - [[package]] name = "typenum" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "ucd-trie" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" - [[package]] name = "unicase" version = "2.6.0" @@ -2202,12 +1795,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "unsafe-libyaml" version = "0.2.5" @@ -2237,17 +1824,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -2426,15 +2002,6 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" -[[package]] -name = "xdg" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" -dependencies = [ - "dirs", -] - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 9fd6ffd..871a94c 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -3,7 +3,6 @@ name = "backend" version = "0.1.0" edition = "2021" authors = ["Dominic Grimm "] -publish = false [[bin]] name = "backend" @@ -12,11 +11,11 @@ build = "build.rs" [[bin]] name = "blogctl" -[profile.release] -codegen-units = 1 -lto = "fat" -strip = true -panic = "abort" +# [profile.release] +# codegen-units = 1 +# lto = "fat" +# strip = true +# panic = "abort" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -28,14 +27,13 @@ askama = "0.11.1" askama_actix = "0.13.0" chrono = { version = "0.4.23", features = ["serde"] } clap = { version = "4.1.4", features = ["derive"] } -comrak = { version = "0.16.0", features = ["shortcodes"] } diesel = { version = "2.0.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "chrono", "r2d2"] } env_logger = "0.10.0" envconfig = "0.10.0" fronma = "0.1.1" lazy_static = "1.4.0" log = "0.4.17" -r2d2_redis = "0.14.0" +pulldown-cmark = { version = "0.9.2", default-features = false, features = ["simd"] } scan_dir = "0.3.3" serde = { version = "1.0.152", features = ["derive"] } serde_yaml = "0.9.17" diff --git a/backend/Dockerfile b/backend/Dockerfile index 75619c8..6cff241 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -10,11 +10,6 @@ WORKDIR /usr/src/static COPY --from=css /usr/src/scss/dist ./css RUN minify . -r -o . -FROM tdewolff/minify:latest as templates -WORKDIR /usr/src/templates -COPY ./templates . -RUN minify . -r -o . - FROM docker.io/lukemathwalker/cargo-chef:latest-rust-1.67.0 as chef FROM chef as diesel @@ -33,16 +28,11 @@ RUN cargo chef cook --recipe-path recipe.json RUN rm -rf ./src COPY ./build.rs . COPY --from=static /usr/src/static ./static -COPY --from=templates /usr/src/templates ./templates +COPY ./templates ./templates COPY ./src ./src RUN cargo build FROM docker.io/debian:bullseye-slim as runner -LABEL maintainer="Dominic Grimm " \ - org.opencontainers.image.description="Personal blog backend" \ - org.opencontainers.image.licenses="MIT" \ - org.opencontainers.image.source="https://git.dergrimm.net/dergrimm/blog" \ - org.opencontainers.image.url="https://git.dergrimm.net/dergrimm/blog" RUN apt update RUN apt install -y libpq5 RUN apt install -y ca-certificates @@ -50,10 +40,12 @@ RUN apt-get clean RUN apt-get autoremove -y RUN rm -rf /var/lib/{apt,dpkg,cache,log}/ WORKDIR /usr/local/bin +ENV RUST_BACKTRACE=full COPY --from=diesel /usr/local/cargo/bin/diesel . WORKDIR /usr/src/backend COPY ./run.sh . RUN chmod +x ./run.sh COPY ./migrations ./migrations COPY --from=builder /usr/src/backend/target/debug/backend /usr/src/backend/target/debug/blogctl ./bin/ +EXPOSE 80 ENTRYPOINT [ "./run.sh" ] diff --git a/backend/scss/styles.scss b/backend/scss/styles.scss index 6a2541b..e09b872 100644 --- a/backend/scss/styles.scss +++ b/backend/scss/styles.scss @@ -1,88 +1,42 @@ html, body { - margin: 0; - padding: 0; - width: 100vw; min-height: 100vh; +} + +* { + margin: 0; + padding: 0; font-family: "JetBrains Mono", monospace; } -// * { -// font-family: "JetBrains Mono", monospace; -// } - -h1, -h2, -h3 { - text-align: center; -} - -h2 { - text-decoration: underline; -} - -h3 { - font-style: italic; -} - -h4, -h5, -h6 { - font-weight: bold; -} - -a { - text-decoration: none; -} - -hr { - border: none; - border-top: medium solid black; -} - -ul.dashed { - list-style-type: none; - - li:before { - content: "-"; - position: absolute; - // margin-left: -20px; - margin-left: -1rem; - } -} - -table.border-rows { - border-collapse: collapse; - - tr:first-child, - tr:not(:last-child) { - border-bottom: thin solid black; - } - - th, - td { - padding: 1em; - } - - th:not(:last-child), - td:not(:last-child) { - // border: thin solid black; - border-right: thin solid black; - } -} - #wrapper { + width: 75%; margin: 0 auto; - overflow: auto; - min-height: 100vh; - display: flex; - flex-direction: column; } #navbar { display: flex; + margin-bottom: 1%; + + ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + } + + li { + float: left; + } + + a { + display: block; + text-align: center; + padding: 1em; + text-decoration: none; + } } #navbar-brand { @@ -94,138 +48,18 @@ table.border-rows { } } -.navbar-link a, -#navbar-links ul li a { - display: block; - text-align: center; -} - #navbar-links { width: 50%; ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow: hidden; float: right; - - li { - float: left; - - &:not(:first-of-type) a { - padding-left: 1rem; - } - } } } -#main-wrapper { - flex: 1; - padding: 1.5% 3%; -} - -#footer { - font-size: small; - text-align: center; -} - -#status-code { - text-align: center; -} - -#status-code-message { - font-size: small; -} - -#post-index { - li:not(:last-child) { - margin-bottom: 1rem; - } +#content { + padding: 3%; } .double-border { border: 5px double black; } - -.section-margin { - margin-top: 1%; -} - -.section-light-padding { - padding: 1%; -} - -.breadcrumb { - padding: 1% 0; - - ul { - display: flex; - flex-wrap: wrap; - list-style: none; - margin: 0; - padding: 0; - } - - li:not(:last-child)::after { - display: inline-block; - margin: 0 0.5rem; - content: ">"; - } -} - -.wysiwyg { - hr { - width: 50%; - } - - ul { - @extend ul.dashed; - } - - table { - @extend table.border-rows; - - margin: 0 auto; - } - - p > code, - li > code, - dd > code, - td > code { - word-wrap: break-word; - box-decoration-break: clone; - padding: 0.1rem 0.3rem 0.2rem; - border: thin solid black; - } - - pre { - padding: 0 1rem; - border: thin solid black; - overflow-x: scroll; - } -} - -@media only screen and (max-width: 600px) { - #wrapper { - width: 100%; - } -} - -@media only screen and (min-width: 600px) { - #wrapper { - width: 75%; - } -} - -@media only screen and (min-width: 768px) { -} - -@media only screen and (min-width: 992px) { -} - -@media only screen and (min-width: 1200px) { - #wrapper { - width: 50%; - } -} diff --git a/backend/src/bin/backend.rs b/backend/src/bin/backend.rs index 5aa2ac8..539d84b 100644 --- a/backend/src/bin/backend.rs +++ b/backend/src/bin/backend.rs @@ -1,3 +1,4 @@ +use diesel::QueryDsl; #[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; @@ -5,23 +6,104 @@ use tikv_jemallocator::Jemalloc; #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; -use actix_web::{middleware, App, HttpServer}; +use actix_web::{get, http::StatusCode, middleware, web, App, HttpResponse, HttpServer}; +use actix_web_static_files::ResourceFiles; +use askama_actix::{Template, TemplateToResponse}; +use diesel::prelude::*; + +use backend::*; + +include!(concat!(env!("OUT_DIR"), "/generated.rs")); + +mod filters { + pub fn cmark(s: T) -> ::askama::Result { + let s = s.to_string(); + + let options = pulldown_cmark::Options::empty(); + let parser = pulldown_cmark::Parser::new_ext(&s, options); + + let mut html_output = String::with_capacity(s.len() * 3 / 2); + pulldown_cmark::html::push_html(&mut html_output, parser); + + Ok(html_output) + } +} + +#[derive(Template)] +#[template(path = "status_code.html")] +struct StatusCodeTemplate { + status_code: StatusCode, + message: Option, +} + +#[derive(Template)] +#[template(path = "posts/{slug}.html")] +struct PostBySlugTemplate { + post: db::models::Post, +} + +async fn not_found() -> HttpResponse { + StatusCodeTemplate { + status_code: StatusCode::NOT_FOUND, + message: None, + } + .to_response() +} + +#[get("/posts/{slug}")] +async fn post_by_slug(db_pool: web::Data, path: web::Path) -> HttpResponse { + let slug = path.into_inner(); + + let conn = &mut match db_pool.get() { + Ok(x) => x, + Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)), + }; + + let post = match db::schema::posts::table + .filter(db::schema::posts::slug.eq(&slug)) + .filter(db::schema::posts::active) + .first::(conn) + .optional() + { + Ok(x) => x, + Err(e) => { + dbg!(&e); + return HttpResponse::InternalServerError().body(format!("{:?}", e)); + } + }; + + match post { + Some(x) => PostBySlugTemplate { post: x }.to_response(), + None => { + let mut resp = StatusCodeTemplate { + status_code: StatusCode::NOT_FOUND, + message: None, + } + .to_response(); + *resp.status_mut() = StatusCode::NOT_FOUND; + + resp + } + } +} #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); - log::info!( - "Listening to requests at {}", - backend::config::CONFIG.bind_url - ); + log::info!("Listening to requests at http://0.0.0.0:80"); HttpServer::new(move || { + let generated = generate(); + App::new() .wrap(middleware::Compress::default()) .wrap(middleware::Logger::default()) - .configure(backend::web::init) + .app_data(web::Data::new(db::pool().unwrap())) + .service(post_by_slug) + .service(ResourceFiles::new("/static", generated)) + .default_service(web::route().to(not_found)) }) - .bind(&backend::config::CONFIG.bind_url) + .bind("0.0.0.0:80") .unwrap() .run() .await diff --git a/backend/src/bin/blogctl.rs b/backend/src/bin/blogctl.rs index fc78ab3..5a7f298 100644 --- a/backend/src/bin/blogctl.rs +++ b/backend/src/bin/blogctl.rs @@ -9,7 +9,6 @@ use anyhow::{bail, Result}; use chrono::prelude::*; use clap::{Parser, Subcommand}; use diesel::prelude::*; -use r2d2_redis::redis; use scan_dir::ScanDir; use serde::{Deserialize, Serialize}; use std::fs; @@ -28,9 +27,6 @@ struct Cli { enum Commands { #[clap(about = "Imports new posts")] Import, - - #[clap(about = "Clears redis cache")] - Clear, } #[derive(Deserialize, Serialize, Debug)] @@ -54,137 +50,88 @@ struct Post { fn main() -> Result<()> { match Cli::parse().commands { Commands::Import => { - let db_conn = &mut db::establish_connection()?; - let redis_conn = &mut cache::establish_connection()?; + let conn = &mut db::establish_connection()?; - let posts = ScanDir::dirs() - .read("/blog", |iter| { - iter.map(|(entry, _)| { - let path = entry.path().join("post.md"); - let src = fs::read_to_string(&path)?; - let frontmatter = match fronma::parser::parse::(&src) { - Ok(x) => x, - Err(x) => bail!("Error parsing frontmatter: {:?}", x), - }; - - Ok(Post { - path, - frontmatter: frontmatter.headers, - content: frontmatter.body.to_string(), - }) - }) - .collect::>>() - })?? - .into_iter() - .map(|post| -> Result<_> { - let trimmed = PostFrontmatter { - id: post.frontmatter.id, - name: post.frontmatter.name.trim().to_string(), - slug: post.frontmatter.slug.trim().to_string(), - description: post.frontmatter.description.trim().to_string(), - published_at: post.frontmatter.published_at, - edited_at: post.frontmatter.edited_at, - active: post.frontmatter.active, + for post in ScanDir::dirs().read("/blog", |iter| { + iter.map(|(entry, _)| { + let path = entry.path().join("post.md"); + let src = fs::read_to_string(&path)?; + let frontmatter = match fronma::parser::parse::(&src) { + Ok(x) => x, + Err(x) => bail!("Error parsing frontmatter: {:?}", x), }; - let content = post.content.trim(); - if let Some(id) = trimmed.id { + Ok(Post { + path, + frontmatter: frontmatter.headers, + content: frontmatter.body.to_string(), + }) + }) + .collect::>>() + })?? { + let content = post.content.trim(); + + if let Some(id) = post.frontmatter.id { + diesel::update(db::schema::posts::table) + .filter(db::schema::posts::id.eq(id)) + .set(db::models::UpdatePost { + name: Some(&post.frontmatter.name), + slug: Some(&post.frontmatter.slug), + description: Some(&post.frontmatter.description), + content: Some(content), + published_at: Some(post.frontmatter.published_at), + edited_at: Some(post.frontmatter.edited_at), + active: Some(post.frontmatter.active), + }) + .execute(conn)?; + } else { + let id = if let Some(id) = db::schema::posts::table + .select(db::schema::posts::id) + .filter(db::schema::posts::slug.eq(&post.frontmatter.slug)) + .first::(conn) + .optional()? + { diesel::update(db::schema::posts::table) .filter(db::schema::posts::id.eq(id)) .set(db::models::UpdatePost { - name: Some(&trimmed.name), - slug: Some(&trimmed.slug), - description: Some(&trimmed.description), + name: Some(&post.frontmatter.name), + slug: None, + description: Some(&post.frontmatter.description), content: Some(content), - published_at: Some(trimmed.published_at), - edited_at: Some(trimmed.edited_at), - active: Some(trimmed.active), + published_at: Some(post.frontmatter.published_at), + edited_at: Some(post.frontmatter.edited_at), + active: Some(post.frontmatter.active), }) - .execute(db_conn)?; + .execute(conn)?; - Ok(id) + id } else { - let id = if let Some(id) = db::schema::posts::table - .select(db::schema::posts::id) - .filter(db::schema::posts::slug.eq(&trimmed.slug)) - .first::(db_conn) - .optional()? - { - diesel::update(db::schema::posts::table) - .filter(db::schema::posts::id.eq(id)) - .set(db::models::UpdatePost { - name: Some(&trimmed.name), - slug: None, - description: Some(&trimmed.description), - content: Some(content), - published_at: Some(trimmed.published_at), - edited_at: Some(trimmed.edited_at), - active: Some(trimmed.active), - }) - .execute(db_conn)?; + diesel::insert_into(db::schema::posts::table) + .values(db::models::NewPost { + name: &post.frontmatter.name, + slug: &post.frontmatter.slug, + description: &post.frontmatter.description, + content: content, + published_at: post.frontmatter.published_at, + edited_at: post.frontmatter.edited_at, + active: post.frontmatter.active, + }) + .returning(db::schema::posts::id) + .get_result::(conn)? + }; - id - } else { - diesel::insert_into(db::schema::posts::table) - .values(db::models::NewPost { - name: &trimmed.name, - slug: &trimmed.slug, - description: &trimmed.description, - content: content, - published_at: trimmed.published_at, - edited_at: trimmed.edited_at, - active: trimmed.active, - }) - .returning(db::schema::posts::id) - .get_result::(db_conn)? - }; - - fs::write( - post.path, - format!( - "---\n{}---\n\n{}\n", - serde_yaml::to_string(&PostFrontmatter { - id: Some(id), - ..trimmed - })?, - content - ), - )?; - - Ok(id) - } - }) - .collect::>>()?; - - let ids = db::schema::posts::table - .select(db::schema::posts::id) - .load::(db_conn)?; - - diesel::delete( - db::schema::posts::table - .filter(diesel::dsl::not(db::schema::posts::id.eq_any(posts))), - ) - .execute(db_conn)?; - - for id in ids { - redis::cmd("DEL") - .arg(cache::keys::post_content(id)) - .query::<()>(redis_conn)?; - } - - Ok(()) - } - Commands::Clear => { - let db_conn = &mut db::establish_connection()?; - let redis_conn = &mut cache::establish_connection()?; - - for id in db::schema::posts::table - .select(db::schema::posts::id) - .load::(db_conn)? - { - redis::cmd("DEL") - .arg(cache::keys::post_content(id)) - .query::<()>(redis_conn)?; + fs::write( + post.path, + format!( + "---\n{}---\n{}", + serde_yaml::to_string(&PostFrontmatter { + id: Some(id), + ..post.frontmatter + })?, + post.content + ), + )?; + } } Ok(()) diff --git a/backend/src/cache.rs b/backend/src/cache.rs deleted file mode 100644 index 5fe7070..0000000 --- a/backend/src/cache.rs +++ /dev/null @@ -1,28 +0,0 @@ -use anyhow::Result; -use lazy_static::lazy_static; -use r2d2_redis::{r2d2, redis, RedisConnectionManager}; - -use crate::config; - -pub type RedisPool = r2d2::Pool; -pub type ConnectionPool = r2d2::PooledConnection; - -pub fn establish_connection() -> Result { - Ok(redis::Client::open(config::CONFIG.redis_url.as_str())?.get_connection()?) -} - -pub fn pool() -> Result { - Ok(r2d2::Pool::builder().build(RedisConnectionManager::new( - config::CONFIG.redis_url.as_str(), - )?)?) -} - -lazy_static! { - pub static ref POOL: RedisPool = pool().unwrap(); -} - -pub mod keys { - pub fn post_content(id: i32) -> String { - format!("post_content:{}", id) - } -} diff --git a/backend/src/config.rs b/backend/src/config.rs index 282d108..632be35 100644 --- a/backend/src/config.rs +++ b/backend/src/config.rs @@ -1,19 +1,11 @@ + use envconfig::Envconfig; use lazy_static::lazy_static; #[derive(Envconfig, Debug)] pub struct Config { - #[envconfig(from = "BACKEND_BIND_URL")] - pub bind_url: String, - #[envconfig(from = "BACKEND_DB_URL")] pub db_url: String, - - #[envconfig(from = "BACKEND_REDIS_URL")] - pub redis_url: String, - - #[envconfig(from = "BACKEND_CACHE_POST_CONTENT_TTL")] - pub cache_post_content_ttl: usize, } lazy_static! { diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 5fee41d..7cb3263 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -1,5 +1,2 @@ -pub mod cache; pub mod config; pub mod db; -pub mod markdown; -pub mod web; diff --git a/backend/src/markdown.rs b/backend/src/markdown.rs deleted file mode 100644 index 298df01..0000000 --- a/backend/src/markdown.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub fn to_html(src: &str) -> String { - let adapter = comrak::plugins::syntect::SyntectAdapter::new("InspiredGitHub"); - let options = comrak::ComrakOptions { - extension: comrak::ComrakExtensionOptions { - strikethrough: true, - tagfilter: true, - table: true, - autolink: true, - tasklist: true, - superscript: true, - header_ids: Some("__blog-content_".to_string()), - footnotes: true, - description_lists: true, - front_matter_delimiter: None, - shortcodes: true, - }, - parse: comrak::ComrakParseOptions { - smart: true, - ..comrak::ComrakParseOptions::default() - }, - ..comrak::ComrakOptions::default() - }; - let mut plugins = comrak::ComrakPlugins::default(); - - plugins.render.codefence_syntax_highlighter = Some(&adapter); - - comrak::markdown_to_html_with_plugins(src, &options, &plugins) -} diff --git a/backend/src/web/mod.rs b/backend/src/web/mod.rs deleted file mode 100644 index 0b092f5..0000000 --- a/backend/src/web/mod.rs +++ /dev/null @@ -1,176 +0,0 @@ -use actix_web::{get, http, web, HttpResponse}; -use actix_web_static_files::ResourceFiles; -use askama_actix::TemplateToResponse; -use diesel::prelude::*; -use r2d2_redis::redis; -use std::ops::DerefMut; - -use crate::{cache, config, db, markdown}; - -pub mod templates; - -pub mod static_dir { - include!(concat!(env!("OUT_DIR"), "/generated.rs")); -} - -async fn not_found() -> HttpResponse { - let mut resp = templates::StatusCode { - status_code: http::StatusCode::NOT_FOUND, - message: Some("maybe try a correct url?".to_string()), - } - .to_response(); - *resp.status_mut() = http::StatusCode::NOT_FOUND; - - resp -} - -#[get("/posts")] -async fn posts(db_pool: web::Data) -> HttpResponse { - let db_conn = &mut match db_pool.get() { - Ok(x) => x, - Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)), - }; - - let posts = match db::schema::posts::table - .filter(db::schema::posts::active) - .order(db::schema::posts::published_at.desc()) - .load::(db_conn) - { - Ok(x) => x, - Err(e) => { - return HttpResponse::InternalServerError().body(format!("{:?}", e)); - } - }; - - templates::Posts { posts }.to_response() -} - -#[get("/")] -async fn index() -> HttpResponse { - templates::Index.to_response() -} - -#[get("/about")] -async fn about() -> HttpResponse { - templates::About.to_response() -} - -#[get("/posts/{slug}")] -async fn post_by_slug( - db_pool: web::Data, - redis_pool: web::Data, - path: web::Path, -) -> HttpResponse { - let slug = path.into_inner(); - - let db_conn = &mut match db_pool.get() { - Ok(x) => x, - Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)), - }; - let redis_conn = &mut match redis_pool.get() { - Ok(x) => x, - Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)), - }; - - let post_stripped: Option<(i32, String)> = match db::schema::posts::table - .select((db::schema::posts::id, db::schema::posts::name)) - .filter(db::schema::posts::slug.eq(&slug)) - .filter(db::schema::posts::active) - .get_result::<(i32, String)>(db_conn) - .optional() - { - Ok(x) => x, - Err(e) => { - return HttpResponse::InternalServerError().body(format!("{:?}", e)); - } - }; - - match post_stripped { - Some(stripped) => { - let (stripped_id, stripped_name) = stripped; - - let key = cache::keys::post_content(stripped_id); - - match match redis::cmd("GET") - .arg(&key) - .query::>(redis_conn.deref_mut()) - { - Ok(x) => x, - Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)), - } { - Some(s) => templates::PostBySlug { - name: stripped_name, - slug, - content: s, - } - .to_response(), - None => { - let post = match db::schema::posts::table - .filter(db::schema::posts::id.eq(stripped_id)) - .first::(db_conn) - { - Ok(x) => x, - Err(e) => { - return HttpResponse::InternalServerError().body(format!("{:?}", e)); - } - }; - - let html = markdown::to_html(&post.content); - - match redis::cmd("SET") - .arg(&key) - .arg(&html) - .query::>(redis_conn.deref_mut()) - { - Ok(x) => x, - Err(e) => { - return HttpResponse::InternalServerError().body(format!("{:?}", e)) - } - }; - if let Err(e) = redis::cmd("EXPIRE") - .arg(key) - .arg(config::CONFIG.cache_post_content_ttl) - .query::<()>(redis_conn.deref_mut()) - { - return HttpResponse::InternalServerError().body(format!("{:?}", e)); - } - - templates::PostBySlug { - name: post.name, - slug: post.slug, - content: html, - } - .to_response() - } - } - } - None => { - let mut resp = templates::StatusCode { - status_code: http::StatusCode::NOT_FOUND, - message: Some("this post does not exists... yet".to_string()), - } - .to_response(); - *resp.status_mut() = http::StatusCode::NOT_FOUND; - - resp - } - } -} - -fn setup_routes(cfg: &mut web::ServiceConfig) { - let generated = static_dir::generate(); - - cfg.service(index) - .service(about) - .service(posts) - .service(ResourceFiles::new("/static", generated)) - .service(post_by_slug) - .default_service(web::route().to(not_found)); -} - -pub fn init(cfg: &mut web::ServiceConfig) { - cfg.app_data(web::Data::new(db::pool().unwrap())) - .app_data(web::Data::new(cache::pool().unwrap())); - - setup_routes(cfg); -} diff --git a/backend/src/web/templates.rs b/backend/src/web/templates.rs deleted file mode 100644 index 2abe2c2..0000000 --- a/backend/src/web/templates.rs +++ /dev/null @@ -1,33 +0,0 @@ -use actix_web::http; -use askama_actix::Template; - -use crate::db; - -#[derive(Template)] -#[template(path = "status_code.html")] -pub struct StatusCode { - pub status_code: http::StatusCode, - pub message: Option, -} - -#[derive(Template)] -#[template(path = "web/index.html")] -pub struct Index; - -#[derive(Template)] -#[template(path = "web/about.html")] -pub struct About; - -#[derive(Template)] -#[template(path = "web/posts/index.html")] -pub struct Posts { - pub posts: Vec, -} - -#[derive(Template)] -#[template(path = "web/posts/{slug}.html")] -pub struct PostBySlug { - pub name: String, - pub slug: String, - pub content: String, -} diff --git a/backend/templates/base.html b/backend/templates/base.html index 30fb7cf..c238438 100644 --- a/backend/templates/base.html +++ b/backend/templates/base.html @@ -7,7 +7,7 @@ {% block title %}{% endblock %} | dergrimm's blog - + @@ -15,39 +15,19 @@
-
- -
- -
-
+ -
- -
- {% block content %}{% endblock %} -
+
+ {% block content %}{% endblock %}
- -
diff --git a/backend/templates/posts/{slug}.html b/backend/templates/posts/{slug}.html new file mode 100644 index 0000000..e43530a --- /dev/null +++ b/backend/templates/posts/{slug}.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block title %}{{ post.name }}{% endblock %} + +{% block head %}{% endblock %} + +{% block content %} +
+ {{ post.content|cmark|safe }} +
+{% endblock %} diff --git a/backend/templates/status_code.html b/backend/templates/status_code.html index 9d81d00..d208f86 100644 --- a/backend/templates/status_code.html +++ b/backend/templates/status_code.html @@ -1,19 +1,14 @@ {% extends "base.html" %} -{% block title %}{{ status_code|lower }}{% endblock %} +{% block title %}{{ status_code }}{% endblock %} {% block head %}{% endblock %} -{% block breadcrumb %}{% endblock %} - {% block content %} -
-

{{ status_code }}!

- {% match message %} - {% when Some with (x) %} -

{{ x }}

- {% when None %} - {% endmatch %} -

:(

-
+

{{ status_code }}!

+ {% match message %} + {% when Some with (x) %} +

{{ x }}

+ {% when None %} + {% endmatch %} {% endblock %} diff --git a/backend/templates/web/about.html b/backend/templates/web/about.html deleted file mode 100644 index d06dd2e..0000000 --- a/backend/templates/web/about.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "base.html" %} - -{% block title %}index{% endblock %} - -{% block head %}{% endblock %} - -{% block breadcrumb %}{% endblock %} - -{% block content %} -

...fearlessly conquering the world of backend

-

About

-

Hey, I'm Dominic (aka. dergrimm) and am currently a student going to school in Germany.

-

- You can contact me at: - dominic@dergrimm.net -

-{% endblock %} diff --git a/backend/templates/web/index.html b/backend/templates/web/index.html deleted file mode 100644 index 36f1e74..0000000 --- a/backend/templates/web/index.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base.html" %} - -{% block title %}index{% endblock %} - -{% block head %}{% endblock %} - -{% block breadcrumb %}{% endblock %} - -{% block content %} -

This is my site

-

Hey, I'm Dominic (aka. dergrimm) and this is my blog!

-

I mostly plan to talk about modern tech and server side stuff like Rust, Crystal, C, databases and APIs.

-

Keep posted by following my feed.

-{% endblock %} diff --git a/backend/templates/web/posts/index.html b/backend/templates/web/posts/index.html deleted file mode 100644 index 3a6a9c1..0000000 --- a/backend/templates/web/posts/index.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "base.html" %} - -{% block title %}posts{% endblock %} - -{% block head %}{% endblock %} - -{% block breadcrumb %} -
  • posts
  • -{% endblock %} - -{% block content %} -
      - {% for post in posts %} -
    • - - {{ post.name }} - ({{ post.published_at }}{% match post.edited_at %}{% when Some with (x) %} -> {{ x }}{% when None %}{% endmatch %}) - -
      - {{ post.description }} -
    • - {% endfor %} -
    -{% endblock %} diff --git a/backend/templates/web/posts/{slug}.html b/backend/templates/web/posts/{slug}.html deleted file mode 100644 index 1f1754d..0000000 --- a/backend/templates/web/posts/{slug}.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ name }}{% endblock %} - -{% block head %}{% endblock %} - -{% block breadcrumb %} -
  • posts
  • -
  • {{ slug }}
  • -{% endblock %} - -{% block content %} -
    - {{content|safe }} -
    -{% endblock %} diff --git a/blog/hello_world/post.md b/blog/hello_world/post.md new file mode 100644 index 0000000..3fc95f6 --- /dev/null +++ b/blog/hello_world/post.md @@ -0,0 +1,15 @@ +--- +id: 1 +name: Hello world! +slug: hello_world +description: Hello world to the internet. Set up my first blog! +published_at: 2023-02-06 +edited_at: null +active: true +--- + +# Hello world! + +I just set up my first blog and am really proud of it! + +So anyway, here I am. diff --git a/docker-compose.yml b/docker-compose.yml index 5fd4c0c..6f22cf8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db: - image: docker.io/postgres:15-alpine + image: docker.io/postgres:alpine restart: always environment: POSTGRES_USER: ${POSTGRES_USER} @@ -11,45 +11,27 @@ services: - db:/var/lib/postgresql/data adminer: - image: docker.io/adminer:4-standalone + image: docker.io/adminer:standalone restart: always ports: - 8080:8080 depends_on: - db - redis: - image: docker.io/redis:7-alpine - restart: always - - redis-commander: - image: rediscommander/redis-commander:latest - restart: always - environment: - REDIS_HOSTS: local:redis:6379 - ports: - - 8081:8081 - depends_on: - - redis - - blog: - image: git.dergrimm.net/dergrimm/blog:latest + backend: + image: git.dergrimm.net/dergrimm/blog_backend:latest build: context: ./backend restart: always command: worker environment: - BACKEND_BIND_URL: 0.0.0.0:80 BACKEND_DB_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_USER} - BACKEND_REDIS_URL: redis://redis - BACKEND_CACHE_POST_CONTENT_TTL: 3600 volumes: - ./blog:/blog ports: - 80:80 depends_on: - db - - redis volumes: db: