Update
This commit is contained in:
parent
94fb270008
commit
584c07ff23
22 changed files with 539 additions and 187 deletions
|
@ -31,3 +31,11 @@ insert_final_newline = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.scss]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
backend/templates
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"**/templates/**/*.html": "jinja-html"
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ Dockerfile
|
||||||
.dockerignore
|
.dockerignore
|
||||||
vendor/
|
vendor/
|
||||||
example/
|
example/
|
||||||
|
static/
|
||||||
|
|
180
backend/Cargo.lock
generated
180
backend/Cargo.lock
generated
|
@ -183,6 +183,18 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-web-static-files"
|
||||||
|
version = "4.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830ce9c2daaefe6fc8a484774b9fc9e79ab5b4685064c85d50fd55e820b9a6c5"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"derive_more",
|
||||||
|
"futures-util",
|
||||||
|
"static-files",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
|
@ -251,6 +263,65 @@ dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb98f10f371286b177db5eeb9a6e5396609555686a35e1d4f7b9a9c6d8af0139"
|
||||||
|
dependencies = [
|
||||||
|
"askama_derive",
|
||||||
|
"askama_escape",
|
||||||
|
"askama_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_actix"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c52f74f8382a142ecfc052100b21abc33f2c069e20fe345808e7ed914b179449"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"askama",
|
||||||
|
"askama_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_derive"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71"
|
||||||
|
dependencies = [
|
||||||
|
"askama_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_escape"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "askama_shared"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf722b94118a07fcbc6640190f247334027685d4e218b794dbfe17c32bf38ed0"
|
||||||
|
dependencies = [
|
||||||
|
"askama_escape",
|
||||||
|
"humansize",
|
||||||
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
|
"nom",
|
||||||
|
"num-traits",
|
||||||
|
"percent-encoding",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"syn",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -262,7 +333,10 @@ name = "backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
"actix-web-static-files",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"askama",
|
||||||
|
"askama_actix",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"diesel",
|
"diesel",
|
||||||
|
@ -271,9 +345,11 @@ dependencies = [
|
||||||
"fronma",
|
"fronma",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
"pulldown-cmark",
|
||||||
"scan_dir",
|
"scan_dir",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml 0.9.17",
|
"serde_yaml 0.9.17",
|
||||||
|
"static-files",
|
||||||
"tikv-jemallocator",
|
"tikv-jemallocator",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -376,6 +452,16 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "change-detection"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "159fa412eae48a1d94d0b9ecdb85c97ce56eb2a347c62394d3fdbf221adabc1a"
|
||||||
|
dependencies = [
|
||||||
|
"path-matchers",
|
||||||
|
"path-slash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.23"
|
version = "0.4.23"
|
||||||
|
@ -710,6 +796,7 @@ dependencies = [
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -739,6 +826,12 @@ version = "0.27.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
|
checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
|
@ -808,6 +901,12 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humansize"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -992,6 +1091,22 @@ version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -1013,6 +1128,16 @@ dependencies = [
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
|
@ -1092,6 +1217,21 @@ version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "path-matchers"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36cd9b72a47679ec193a5f0229d9ab686b7bd45e1fbc59ccf953c9f3d83f7b2b"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "path-slash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "498a099351efa4becc6a19c72aa9270598e8fd274ca47052e37455241c88b696"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
@ -1164,6 +1304,17 @@ dependencies = [
|
||||||
"unicode-ident",
|
"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]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
@ -1430,6 +1581,17 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static-files"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64712ea1e3e140010e1d9605872ba205afa2ab5bd38191cc6ebd248ae1f6a06b"
|
||||||
|
dependencies = [
|
||||||
|
"change-detection",
|
||||||
|
"mime_guess",
|
||||||
|
"path-slash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -1561,6 +1723,15 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.37"
|
version = "0.1.37"
|
||||||
|
@ -1588,6 +1759,15 @@ version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicase"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||||
|
dependencies = [
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
|
|
|
@ -6,21 +6,25 @@ authors = ["Dominic Grimm <dominic@dergrimm.net>"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "backend"
|
name = "backend"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "blogctl"
|
name = "blogctl"
|
||||||
|
|
||||||
[profile.release]
|
# [profile.release]
|
||||||
codegen-units = 1
|
# codegen-units = 1
|
||||||
lto = "fat"
|
# lto = "fat"
|
||||||
strip = true
|
# strip = true
|
||||||
panic = "abort"
|
# panic = "abort"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4.3.0"
|
actix-web = "4.3.0"
|
||||||
|
actix-web-static-files = "4.0.0"
|
||||||
anyhow = { version = "1.0.69", features = ["backtrace"] }
|
anyhow = { version = "1.0.69", features = ["backtrace"] }
|
||||||
|
askama = "0.11.1"
|
||||||
|
askama_actix = "0.13.0"
|
||||||
chrono = { version = "0.4.23", features = ["serde"] }
|
chrono = { version = "0.4.23", features = ["serde"] }
|
||||||
clap = { version = "4.1.4", features = ["derive"] }
|
clap = { version = "4.1.4", features = ["derive"] }
|
||||||
diesel = { version = "2.0.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "chrono", "r2d2"] }
|
diesel = { version = "2.0.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "chrono", "r2d2"] }
|
||||||
|
@ -29,9 +33,14 @@ envconfig = "0.10.0"
|
||||||
fronma = "0.1.1"
|
fronma = "0.1.1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
pulldown-cmark = { version = "0.9.2", default-features = false, features = ["simd"] }
|
||||||
scan_dir = "0.3.3"
|
scan_dir = "0.3.3"
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_yaml = "0.9.17"
|
serde_yaml = "0.9.17"
|
||||||
|
static-files = "0.2.3"
|
||||||
|
|
||||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||||
tikv-jemallocator = "0.5.0"
|
tikv-jemallocator = "0.5.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
static-files = "0.2.3"
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
FROM codycraven/sassc:latest as css
|
||||||
|
WORKDIR /usr/src/scss
|
||||||
|
RUN mkdir dist
|
||||||
|
WORKDIR /usr/src/scss/src
|
||||||
|
COPY ./scss .
|
||||||
|
RUN find . -name "*.scss" -type f | xargs -I % sh -c 'sassc % > ../dist/$(basename -- "%" .scss).css'
|
||||||
|
|
||||||
|
FROM tdewolff/minify:latest as static
|
||||||
|
WORKDIR /usr/src/static
|
||||||
|
COPY --from=css /usr/src/scss/dist ./css
|
||||||
|
RUN minify . -r -o .
|
||||||
|
|
||||||
FROM docker.io/lukemathwalker/cargo-chef:latest-rust-1.67.0 as chef
|
FROM docker.io/lukemathwalker/cargo-chef:latest-rust-1.67.0 as chef
|
||||||
|
|
||||||
FROM chef as diesel
|
FROM chef as diesel
|
||||||
|
@ -12,10 +24,13 @@ RUN cargo chef prepare --recipe-path recipe.json
|
||||||
FROM chef as builder
|
FROM chef as builder
|
||||||
WORKDIR /usr/src/backend
|
WORKDIR /usr/src/backend
|
||||||
COPY --from=planner /usr/src/backend/recipe.json .
|
COPY --from=planner /usr/src/backend/recipe.json .
|
||||||
RUN cargo chef cook --release --recipe-path recipe.json
|
RUN cargo chef cook --recipe-path recipe.json
|
||||||
RUN rm -rf ./src
|
RUN rm -rf ./src
|
||||||
|
COPY ./build.rs .
|
||||||
|
COPY --from=static /usr/src/static ./static
|
||||||
|
COPY ./templates ./templates
|
||||||
COPY ./src ./src
|
COPY ./src ./src
|
||||||
RUN cargo build --release
|
RUN cargo build
|
||||||
|
|
||||||
FROM docker.io/debian:bullseye-slim as runner
|
FROM docker.io/debian:bullseye-slim as runner
|
||||||
RUN apt update
|
RUN apt update
|
||||||
|
@ -31,6 +46,6 @@ WORKDIR /usr/src/backend
|
||||||
COPY ./run.sh .
|
COPY ./run.sh .
|
||||||
RUN chmod +x ./run.sh
|
RUN chmod +x ./run.sh
|
||||||
COPY ./migrations ./migrations
|
COPY ./migrations ./migrations
|
||||||
COPY --from=builder /usr/src/backend/target/release/backend /usr/src/backend/target/release/blogctl ./bin/
|
COPY --from=builder /usr/src/backend/target/debug/backend /usr/src/backend/target/debug/blogctl ./bin/
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
ENTRYPOINT [ "./run.sh" ]
|
ENTRYPOINT [ "./run.sh" ]
|
||||||
|
|
5
backend/build.rs
Normal file
5
backend/build.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use static_files::resource_dir;
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
resource_dir("./static").build()
|
||||||
|
}
|
|
@ -1,7 +1,3 @@
|
||||||
DROP TABLE posts;
|
DROP TABLE posts;
|
||||||
|
|
||||||
DROP TABLE tags;
|
DROP TABLE tags;
|
||||||
|
|
||||||
DROP INDEX configs_active;
|
|
||||||
|
|
||||||
DROP TABLE configs;
|
|
||||||
|
|
|
@ -1,37 +1,3 @@
|
||||||
CREATE TABLE configs(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
active BOOLEAN NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
description TEXT NOT NULL,
|
|
||||||
copyright TEXT NOT NULL,
|
|
||||||
owner_name TEXT NOT NULL,
|
|
||||||
owner_email TEXT NOT NULL,
|
|
||||||
owner_website TEXT
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX configs_active ON configs(active)
|
|
||||||
WHERE
|
|
||||||
active;
|
|
||||||
|
|
||||||
INSERT INTO
|
|
||||||
configs(
|
|
||||||
active,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
copyright,
|
|
||||||
owner_name,
|
|
||||||
owner_email
|
|
||||||
)
|
|
||||||
VALUES
|
|
||||||
(
|
|
||||||
TRUE,
|
|
||||||
'generic blog',
|
|
||||||
'just a generic blog',
|
|
||||||
'(C) just a generic blog',
|
|
||||||
'generic blog owner',
|
|
||||||
'blog@example.com'
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE tags(
|
CREATE TABLE tags(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT UNIQUE NOT NULL
|
name TEXT UNIQUE NOT NULL
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
DATABASE_URL="$BACKEND_DB_URL" diesel setup \
|
DATABASE_URL="$BACKEND_DB_URL" diesel setup \
|
||||||
--migration-dir ./migrations \
|
--migration-dir ./migrations \
|
||||||
--locked-schema &&
|
--locked-schema &&
|
||||||
./bin/backend run
|
RUST_LOG=info ./bin/backend
|
||||||
|
|
65
backend/scss/styles.scss
Normal file
65
backend/scss/styles.scss
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
font-family: "JetBrains Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
width: 75%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
a {
|
||||||
|
float: left;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar-links {
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
padding: 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.double-border {
|
||||||
|
border: 5px double black;
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
use diesel::QueryDsl;
|
||||||
#[cfg(not(target_env = "msvc"))]
|
#[cfg(not(target_env = "msvc"))]
|
||||||
use tikv_jemallocator::Jemalloc;
|
use tikv_jemallocator::Jemalloc;
|
||||||
|
|
||||||
|
@ -5,42 +6,105 @@ use tikv_jemallocator::Jemalloc;
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL: Jemalloc = Jemalloc;
|
static GLOBAL: Jemalloc = Jemalloc;
|
||||||
|
|
||||||
use actix_web::{
|
use actix_web::{get, http::StatusCode, middleware, web, App, HttpResponse, HttpServer};
|
||||||
http::header,
|
use actix_web_static_files::ResourceFiles;
|
||||||
middleware,
|
use askama_actix::{Template, TemplateToResponse};
|
||||||
web::{self, Data},
|
use diesel::prelude::*;
|
||||||
App, Error, HttpResponse, HttpServer,
|
|
||||||
};
|
|
||||||
use clap::{Parser, Subcommand};
|
|
||||||
|
|
||||||
use backend::*;
|
use backend::*;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||||
#[clap(author, version, about, long_about = None)]
|
|
||||||
struct Cli {
|
mod filters {
|
||||||
#[clap(subcommand)]
|
pub fn cmark<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
|
||||||
commands: Commands,
|
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(Debug, Subcommand)]
|
#[derive(Template)]
|
||||||
enum Commands {
|
#[template(path = "status_code.html")]
|
||||||
#[clap(about = "Starts webserver")]
|
struct StatusCodeTemplate {
|
||||||
Run,
|
status_code: StatusCode,
|
||||||
|
message: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<db::DbPool>, path: web::Path<String>) -> 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::<db::models::Post>(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]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
match Cli::parse().commands {
|
env_logger::init();
|
||||||
Commands::Run => {
|
log::info!("Listening to requests at http://0.0.0.0:80");
|
||||||
std::env::set_var("RUST_LOG", "info");
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
let server = HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
let generated = generate();
|
||||||
.wrap(middleware::Compress::default())
|
|
||||||
.wrap(middleware::Logger::default())
|
App::new()
|
||||||
});
|
.wrap(middleware::Compress::default())
|
||||||
server.bind("0.0.0.0:80").unwrap().run().await
|
.wrap(middleware::Logger::default())
|
||||||
}
|
.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("0.0.0.0:80")
|
||||||
|
.unwrap()
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,9 @@ use chrono::prelude::*;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use scan_dir::ScanDir;
|
use scan_dir::ScanDir;
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use backend::*;
|
use backend::*;
|
||||||
|
|
||||||
|
@ -28,23 +29,9 @@ enum Commands {
|
||||||
Import,
|
Import,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
struct Blog {
|
|
||||||
name: String,
|
|
||||||
description: String,
|
|
||||||
copyright: String,
|
|
||||||
owner: BlogOwner,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct BlogOwner {
|
|
||||||
name: String,
|
|
||||||
email: String,
|
|
||||||
website: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct PostFrontmatter {
|
struct PostFrontmatter {
|
||||||
|
id: Option<i32>,
|
||||||
name: String,
|
name: String,
|
||||||
slug: String,
|
slug: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
@ -55,6 +42,7 @@ struct PostFrontmatter {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Post {
|
struct Post {
|
||||||
|
path: PathBuf,
|
||||||
frontmatter: PostFrontmatter,
|
frontmatter: PostFrontmatter,
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
@ -64,61 +52,86 @@ fn main() -> Result<()> {
|
||||||
Commands::Import => {
|
Commands::Import => {
|
||||||
let conn = &mut db::establish_connection()?;
|
let conn = &mut db::establish_connection()?;
|
||||||
|
|
||||||
let blog: Blog = serde_yaml::from_str(&fs::read_to_string("/blog/blog.yml")?)?;
|
for post in ScanDir::dirs().read("/blog", |iter| {
|
||||||
|
iter.map(|(entry, _)| {
|
||||||
diesel::delete(db::schema::configs::table)
|
let path = entry.path().join("post.md");
|
||||||
.filter(db::schema::configs::active.eq(true))
|
let src = fs::read_to_string(&path)?;
|
||||||
.execute(conn)?;
|
|
||||||
diesel::insert_into(db::schema::configs::table)
|
|
||||||
.values(db::models::NewConfig {
|
|
||||||
active: true,
|
|
||||||
name: &blog.name,
|
|
||||||
description: &blog.description,
|
|
||||||
copyright: &blog.copyright,
|
|
||||||
owner_name: &blog.owner.name,
|
|
||||||
owner_email: &blog.owner.email,
|
|
||||||
owner_website: blog.owner.website.as_deref(),
|
|
||||||
})
|
|
||||||
.execute(conn)?;
|
|
||||||
|
|
||||||
let posts = ScanDir::dirs().read("/blog/posts", |iter| {
|
|
||||||
iter.map(|(entry, name)| {
|
|
||||||
dbg!(&entry, &name);
|
|
||||||
let src = fs::read_to_string(entry.path().join("post.md"))?;
|
|
||||||
let frontmatter = match fronma::parser::parse::<PostFrontmatter>(&src) {
|
let frontmatter = match fronma::parser::parse::<PostFrontmatter>(&src) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(x) => bail!("Error parsing frontmatter: {:?}", x),
|
Err(x) => bail!("Error parsing frontmatter: {:?}", x),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Post {
|
Ok(Post {
|
||||||
frontmatter: PostFrontmatter {
|
path,
|
||||||
name: frontmatter.headers.name.trim().to_string(),
|
frontmatter: frontmatter.headers,
|
||||||
slug: frontmatter.headers.slug.trim().to_string(),
|
content: frontmatter.body.to_string(),
|
||||||
description: frontmatter.headers.description.trim().to_string(),
|
|
||||||
..frontmatter.headers
|
|
||||||
},
|
|
||||||
content: frontmatter.body.trim().to_string(),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()
|
.collect::<Result<Vec<_>>>()
|
||||||
})??;
|
})?? {
|
||||||
dbg!(&posts);
|
let content = post.content.trim();
|
||||||
|
|
||||||
for post in posts {
|
if let Some(id) = post.frontmatter.id {
|
||||||
diesel::delete(db::schema::posts::table)
|
diesel::update(db::schema::posts::table)
|
||||||
.filter(db::schema::posts::slug.eq(&post.frontmatter.slug))
|
.filter(db::schema::posts::id.eq(id))
|
||||||
.execute(conn)?;
|
.set(db::models::UpdatePost {
|
||||||
diesel::insert_into(db::schema::posts::table)
|
name: Some(&post.frontmatter.name),
|
||||||
.values(db::models::NewPost {
|
slug: Some(&post.frontmatter.slug),
|
||||||
name: &post.frontmatter.name,
|
description: Some(&post.frontmatter.description),
|
||||||
slug: &post.frontmatter.slug,
|
content: Some(content),
|
||||||
description: &post.frontmatter.description,
|
published_at: Some(post.frontmatter.published_at),
|
||||||
content: &post.content,
|
edited_at: Some(post.frontmatter.edited_at),
|
||||||
published_at: post.frontmatter.published_at,
|
active: Some(post.frontmatter.active),
|
||||||
edited_at: post.frontmatter.edited_at,
|
})
|
||||||
active: post.frontmatter.active,
|
.execute(conn)?;
|
||||||
})
|
} else {
|
||||||
.execute(conn)?;
|
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::<i32>(conn)
|
||||||
|
.optional()?
|
||||||
|
{
|
||||||
|
diesel::update(db::schema::posts::table)
|
||||||
|
.filter(db::schema::posts::id.eq(id))
|
||||||
|
.set(db::models::UpdatePost {
|
||||||
|
name: Some(&post.frontmatter.name),
|
||||||
|
slug: None,
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
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::<i32>(conn)?
|
||||||
|
};
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
post.path,
|
||||||
|
format!(
|
||||||
|
"---\n{}---\n{}",
|
||||||
|
serde_yaml::to_string(&PostFrontmatter {
|
||||||
|
id: Some(id),
|
||||||
|
..post.frontmatter
|
||||||
|
})?,
|
||||||
|
post.content
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,31 +3,6 @@ use diesel::prelude::*;
|
||||||
|
|
||||||
use crate::db::schema;
|
use crate::db::schema;
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Debug)]
|
|
||||||
#[diesel(table_name = schema::configs)]
|
|
||||||
pub struct Config {
|
|
||||||
pub id: i32,
|
|
||||||
pub active: bool,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub copyright: String,
|
|
||||||
pub owner_name: String,
|
|
||||||
pub owner_email: String,
|
|
||||||
pub owner_website: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Insertable, Debug)]
|
|
||||||
#[diesel(table_name = schema::configs)]
|
|
||||||
pub struct NewConfig<'a> {
|
|
||||||
pub active: bool,
|
|
||||||
pub name: &'a str,
|
|
||||||
pub description: &'a str,
|
|
||||||
pub copyright: &'a str,
|
|
||||||
pub owner_name: &'a str,
|
|
||||||
pub owner_email: &'a str,
|
|
||||||
pub owner_website: Option<&'a str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Debug)]
|
#[derive(Identifiable, Queryable, Debug)]
|
||||||
#[diesel(table_name = schema::tags)]
|
#[diesel(table_name = schema::tags)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
|
@ -65,3 +40,15 @@ pub struct NewPost<'a> {
|
||||||
pub edited_at: Option<NaiveDate>,
|
pub edited_at: Option<NaiveDate>,
|
||||||
pub active: bool,
|
pub active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(AsChangeset, Debug)]
|
||||||
|
#[diesel(table_name = schema::posts)]
|
||||||
|
pub struct UpdatePost<'a> {
|
||||||
|
pub name: Option<&'a str>,
|
||||||
|
pub slug: Option<&'a str>,
|
||||||
|
pub description: Option<&'a str>,
|
||||||
|
pub content: Option<&'a str>,
|
||||||
|
pub published_at: Option<NaiveDate>,
|
||||||
|
pub edited_at: Option<Option<NaiveDate>>,
|
||||||
|
pub active: Option<bool>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,3 @@
|
||||||
diesel::table! {
|
|
||||||
configs {
|
|
||||||
id -> Integer,
|
|
||||||
active -> Bool,
|
|
||||||
name -> Text,
|
|
||||||
description -> Text,
|
|
||||||
copyright -> Text,
|
|
||||||
owner_name -> Text,
|
|
||||||
owner_email -> Text,
|
|
||||||
owner_website -> Nullable<Text>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
tags {
|
tags {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
|
|
0
backend/static/.keep
Normal file
0
backend/static/.keep
Normal file
33
backend/templates/base.html
Normal file
33
backend/templates/base.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>{% block title %}{% endblock %} | dergrimm's blog</title>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.bunny.net" />
|
||||||
|
<link href="https://fonts.bunny.net/css?family=jetbrains-mono:400" rel="stylesheet" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/styles.css" />
|
||||||
|
|
||||||
|
{% block head %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<nav id="navbar" class="double-border">
|
||||||
|
<div id="navbar-brand"><a href="/">dergrimm's blog</a></div>
|
||||||
|
<div id="navbar-links">
|
||||||
|
<ul>
|
||||||
|
<li><a href="/posts">posts</a></li>
|
||||||
|
<li><a href="/about">about</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="content" class="double-border">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
11
backend/templates/posts/{slug}.html
Normal file
11
backend/templates/posts/{slug}.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ post.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="blog">
|
||||||
|
{{ post.content|cmark|safe }}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
14
backend/templates/status_code.html
Normal file
14
backend/templates/status_code.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ status_code }}{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ status_code }}!</h1>
|
||||||
|
{% match message %}
|
||||||
|
{% when Some with (x) %}
|
||||||
|
<p>{{ x }}</p>
|
||||||
|
{% when None %}
|
||||||
|
{% endmatch %}
|
||||||
|
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
||||||
name: dergrimm's blog
|
|
||||||
description: |
|
|
||||||
Just some personal expericences about technology and programming.
|
|
||||||
Follow my RSS feed for more.
|
|
||||||
copyright: (C) 2022 - Dominic Grimm
|
|
||||||
owner:
|
|
||||||
name: Dominic Grimm
|
|
||||||
email: dominic@dergrimm.net
|
|
||||||
website: https://git.dergrimm.net/dergrimm
|
|
|
@ -1,4 +1,5 @@
|
||||||
---
|
---
|
||||||
|
id: 1
|
||||||
name: Hello world!
|
name: Hello world!
|
||||||
slug: hello_world
|
slug: hello_world
|
||||||
description: Hello world to the internet. Set up my first blog!
|
description: Hello world to the internet. Set up my first blog!
|
||||||
|
@ -9,6 +10,6 @@ active: true
|
||||||
|
|
||||||
# Hello world!
|
# Hello world!
|
||||||
|
|
||||||
I just set up my first blog an am really proud of it!
|
I just set up my first blog and am really proud of it!
|
||||||
|
|
||||||
So anyway, here I am.
|
So anyway, here I am.
|
Loading…
Reference in a new issue