initial
This commit is contained in:
parent
1124de1673
commit
7d0e1d2c73
15 changed files with 960 additions and 43 deletions
2
.env
Normal file
2
.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
# create sqlite if it doesn't already exist
|
||||
DATABASE_URL=sqlite:///./test.db
|
46
.forgejo/workflows/test.yml
Normal file
46
.forgejo/workflows/test.yml
Normal file
|
@ -0,0 +1,46 @@
|
|||
name: Run tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
cargo_test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Run tests
|
||||
run: cargo test --all
|
||||
|
||||
cargo_clippy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Run clippy
|
||||
run: cargo clippy --all -- -D warnings
|
||||
|
||||
cargo_fmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Run fmt
|
||||
run: cargo fmt --all -- --check
|
392
Cargo.lock
generated
392
Cargo.lock
generated
|
@ -237,6 +237,21 @@ dependencies = [
|
|||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
|
@ -326,6 +341,12 @@ dependencies = [
|
|||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
|
@ -364,6 +385,20 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.15.6"
|
||||
|
@ -429,6 +464,12 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.16"
|
||||
|
@ -463,6 +504,41 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
|
@ -485,6 +561,43 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"diesel_derives",
|
||||
"itoa",
|
||||
"libsqlite3-sys",
|
||||
"pq-sys",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_derives"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4"
|
||||
dependencies = [
|
||||
"diesel_table_macro_syntax",
|
||||
"dsl_auto_type",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_table_macro_syntax"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
|
||||
dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
|
@ -515,6 +628,32 @@ dependencies = [
|
|||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "dsl_auto_type"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"either",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
|
@ -530,6 +669,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fern"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.35"
|
||||
|
@ -551,9 +699,16 @@ name = "forgejo-pages"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"chrono",
|
||||
"config",
|
||||
"diesel",
|
||||
"dotenvy",
|
||||
"fern",
|
||||
"git2",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -622,6 +777,21 @@ version = "0.31.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.26"
|
||||
|
@ -665,6 +835,12 @@ dependencies = [
|
|||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
|
@ -688,6 +864,29 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
|
@ -806,6 +1005,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
|
@ -858,6 +1063,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json5"
|
||||
version = "0.4.1"
|
||||
|
@ -875,12 +1090,68 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.18.0+1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libssh2-sys",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
|
@ -959,6 +1230,15 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
|
@ -974,6 +1254,24 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.7.3"
|
||||
|
@ -1103,6 +1401,15 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pq-sys"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6cc05d7ea95200187117196eee9edd0644424911821aeb28a18ce60ea0b8793"
|
||||
dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
|
@ -1233,6 +1540,12 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
|
@ -1372,6 +1685,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.96"
|
||||
|
@ -1601,6 +1920,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
@ -1613,6 +1938,73 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
|
@ -10,3 +10,10 @@ actix-web = "4"
|
|||
config = "0.15"
|
||||
log = "0.4"
|
||||
serde = "1"
|
||||
lazy_static = "1.5.0"
|
||||
git2 = "*"
|
||||
chrono = "*"
|
||||
diesel = { version = "2.2.0", features = ["postgres", "sqlite"] }
|
||||
dotenvy = "0.15"
|
||||
toml = "*"
|
||||
fern = "0.7"
|
9
diesel.toml
Normal file
9
diesel.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
# For documentation on how to configure this file,
|
||||
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
|
||||
|
||||
[migrations_directory]
|
||||
dir = "/home/aces/forgejo-pages/migrations"
|
239
src/backends/git.rs
Normal file
239
src/backends/git.rs
Normal file
|
@ -0,0 +1,239 @@
|
|||
use std::borrow::BorrowMut;
|
||||
use std::cell::Ref;
|
||||
use std::cell::RefCell;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::Arc;
|
||||
|
||||
use diesel::Connection;
|
||||
use diesel::QueryResult;
|
||||
use diesel::prelude::*;
|
||||
use crate::conf;
|
||||
use crate::conf::CONFIG;
|
||||
use crate::data::PageError;
|
||||
use crate::data::{self, Page, PageManager};
|
||||
use crate::schema::pages;
|
||||
|
||||
#[derive(diesel::MultiConnection)]
|
||||
enum AnyConnection {
|
||||
Postgresql(PgConnection),
|
||||
Sqlite(SqliteConnection),
|
||||
}
|
||||
|
||||
pub struct GitPage {
|
||||
conn: Arc<AnyConnection>,
|
||||
id: i32,
|
||||
}
|
||||
|
||||
impl GitPage {
|
||||
fn get_connection(&self) -> &mut AnyConnection {
|
||||
}
|
||||
}
|
||||
|
||||
impl Page for GitPage {
|
||||
type Id = i32;
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
fn author(&self) -> String {
|
||||
use crate::schema::pages::dsl::*;
|
||||
|
||||
let connection = self.get_connection();
|
||||
|
||||
let page: Vec<String> = pages
|
||||
.filter(id.eq(self.id))
|
||||
.limit(1)
|
||||
.select(author)
|
||||
.load(connection)
|
||||
.expect("Failed to load page");
|
||||
|
||||
// Return the author, assuming at least one result
|
||||
page.get(0).cloned().unwrap_or_else(|| "Unknown author".to_string())
|
||||
}
|
||||
|
||||
fn routing(&self) -> crate::data::PageRouting {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn version(&self) -> String {
|
||||
use crate::schema::git_page_source::dsl::*;
|
||||
|
||||
let connection = self.get_connection();
|
||||
|
||||
let git_page_source: Vec<String> = crate::schema::git_page_source::table
|
||||
.filter(page_id.eq(self.id))
|
||||
.limit(1)
|
||||
.select(repo_url)
|
||||
.load(connection)
|
||||
.expect("Failed to load git page source");
|
||||
|
||||
git_page_source.get(0).cloned().unwrap_or_else(|| "Unknown version".to_string())
|
||||
}
|
||||
|
||||
fn update(&mut self) -> Result<(), crate::data::PageError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GitPageManager<'a> {
|
||||
pub connection: RefCell<AnyConnection>,
|
||||
pages: Vec<GitPage<'a>>,
|
||||
}
|
||||
|
||||
impl GitPageManager<'_> {
|
||||
pub fn new() -> Self {
|
||||
let connection = AnyConnection::establish("sqlite://git.db").unwrap();
|
||||
GitPageManager {
|
||||
connection: RefCell::new(connection),
|
||||
pages: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Filesystem-based storage
|
||||
// - D [PAGES_TEMP]
|
||||
// - D [git_url]
|
||||
// - D [PAGES_ROOT]
|
||||
// - D [UUID]
|
||||
// - F? CNAME
|
||||
// - F? All other files
|
||||
// - F? .git
|
||||
impl<'a> GitPageManager<'a> {
|
||||
fn create(&mut self, url: String, owner: String) -> Result<&GitPage<'a>, PageError> {
|
||||
// - Prepare data
|
||||
// - Insert page into database (STATUS: FETCHING)
|
||||
// - Clone repo to local storage (temp)
|
||||
// - Gather CNAME and other data from repo
|
||||
// - Validate data (Perform checks)
|
||||
// - Update page in database (STATUS: APPLYING)
|
||||
// - Move repo to final storage location
|
||||
// - Validate
|
||||
// - Update page in database (STATUS: READY)
|
||||
|
||||
// Insert the page into the database
|
||||
let connection = &mut *self.connection.borrow_mut();
|
||||
let page_id: i32 = 0;
|
||||
{
|
||||
use crate::schema::pages::dsl::*;
|
||||
let new_page = crate::models::NewPage {
|
||||
name: url.clone(),
|
||||
author: owner.clone(),
|
||||
status: 1,
|
||||
};
|
||||
|
||||
let res_insert = diesel::insert_into(pages)
|
||||
.values(&new_page)
|
||||
.execute(connection);
|
||||
|
||||
if res_insert.is_err() {
|
||||
return Err(PageError::InternalServerError(res_insert.err().unwrap().to_string()));
|
||||
}
|
||||
|
||||
// Get the ID of the page, given name and author
|
||||
let res_page_id: QueryResult<i32> = pages
|
||||
.filter(name.eq(url.clone()))
|
||||
.filter(author.eq(owner.clone()))
|
||||
.select(id)
|
||||
.first(connection);
|
||||
}
|
||||
{
|
||||
// Git tracking attachment
|
||||
use crate::schema::git_page_source::dsl::*;
|
||||
let res_insert_git = diesel::insert_into(git_page_source)
|
||||
.values(&crate::models::NewGitPageSource {
|
||||
page_id: 0,
|
||||
repo_url: url.clone(),
|
||||
branch: "master".to_string(),
|
||||
})
|
||||
.execute(connection);
|
||||
}
|
||||
|
||||
|
||||
// Clone to filesystem (temp)
|
||||
let temp_path = format!("{}/{}", CONFIG.temp_dir, url);
|
||||
let _ = std::fs::create_dir_all(&temp_path);
|
||||
let res_git_repo = git2::Repository::clone(&url, &temp_path);
|
||||
|
||||
if res_git_repo.is_err() {
|
||||
return Err(PageError::FetchError(res_git_repo.err().unwrap().to_string()));
|
||||
}
|
||||
|
||||
// Open CNAME file
|
||||
let cname_path = format!("{}/CNAME", temp_path);
|
||||
let cname = std::fs::read_to_string(&cname_path);
|
||||
|
||||
// CNAME follows GitHub's rules
|
||||
// Each line is a domain
|
||||
let domains: Vec<String> = cname.unwrap_or("".to_string())
|
||||
.split("\n")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
|
||||
// TODO: Validation step here - Put this off for now
|
||||
|
||||
// Move to final storage location
|
||||
let final_path = format!("{}/{}", CONFIG.pages_root, page_id);
|
||||
let _ = std::fs::create_dir_all(&final_path);
|
||||
let _ = std::fs::rename(&temp_path, &final_path);
|
||||
|
||||
// Update the page in the database (we are now ready)
|
||||
{
|
||||
use crate::schema::pages::dsl::*;
|
||||
let res_update = diesel::update(pages)
|
||||
.filter(id.eq(page_id))
|
||||
.set(status.eq(3))
|
||||
.execute(connection);
|
||||
|
||||
if res_update.is_err() {
|
||||
return Err(PageError::InternalServerError(res_update.err().unwrap().to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the page object
|
||||
let page = GitPage {
|
||||
conn:
|
||||
id: page_id,
|
||||
};
|
||||
|
||||
// Add the page to the list of pages
|
||||
self.pages.push(page);
|
||||
|
||||
// Return the page
|
||||
let res_page = self.page(page_id);
|
||||
|
||||
match res_page {
|
||||
Ok(page) => Ok(page),
|
||||
Err(err) => Err(PageError::InternalServerError("Failed to create page".to_string())),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PageManager<'a, GitPage<'a>> for GitPageManager<'a> {
|
||||
|
||||
fn query(&self, author: String, path: String, host: Option<String>) -> Result<crate::data::PageQueryResult, crate::data::PageError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn page(&self, id: <GitPage<'_> as data::Page>::Id) -> Result<&GitPage<'a>, crate::data::PageError> {
|
||||
let page = self.pages.iter().find(|page| page.id() == id);
|
||||
match page {
|
||||
Some(page) => Ok(page),
|
||||
None => Err(crate::data::PageError::NotFound(format!("Page not found: {}", id))),
|
||||
}
|
||||
}
|
||||
|
||||
fn page_mut(&mut self, id: <GitPage<'_> as data::Page>::Id) -> Result<&mut GitPage<'a>, crate::data::PageError> {
|
||||
let page = self.pages.iter_mut().find(|page| page.id() == id);
|
||||
match page {
|
||||
Some(page) => Ok(page),
|
||||
None => Err(crate::data::PageError::NotFound(format!("Page not found: {}", id))),
|
||||
}
|
||||
}
|
||||
|
||||
fn pages_iter(&'a self) -> impl Iterator<Item = &'a GitPage<'a>> {
|
||||
self.pages.iter()
|
||||
}
|
||||
}
|
1
src/backends/mod.rs
Normal file
1
src/backends/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod git;
|
41
src/conf.rs
41
src/conf.rs
|
@ -1,11 +1,44 @@
|
|||
use lazy_static::lazy_static;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
/* Variables */
|
||||
|
||||
const CONFIG_PREFIX: &str = "FJ_PAGES_";
|
||||
|
||||
const CONFIG_DEFAULT: &str = r#"
|
||||
[domain]
|
||||
# The domain of the website
|
||||
domain = "*"
|
||||
|
||||
# The temporary directory for storing files
|
||||
temp_dir = "/tmp"
|
||||
"#;
|
||||
|
||||
lazy_static! {
|
||||
#[derive(Debug)]
|
||||
pub static ref CONFIG: Config = {
|
||||
// Identify path of the configuration file
|
||||
let path = std::env::var(format!("{}CONFIG_PATH", CONFIG_PREFIX)).unwrap_or("config.toml".to_string());
|
||||
// Read the configuration file
|
||||
let result_config = std::fs::read_to_string(path)
|
||||
.unwrap_or(CONFIG_DEFAULT.to_string());
|
||||
// Parse the configuration file
|
||||
toml::from_str(&result_config)
|
||||
.expect("Failed to parse configuration file")
|
||||
};
|
||||
}
|
||||
|
||||
/* Structures */
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct Domain {
|
||||
|
||||
// Regex is allowed
|
||||
domains: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub domain: Domain
|
||||
pub domain: Domain,
|
||||
pub temp_dir: String,
|
||||
pub pages_root: String,
|
||||
}
|
98
src/data.rs
Normal file
98
src/data.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
/// Data storage and retrieval
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Data */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub enum PageError {
|
||||
NotFound(String),
|
||||
Unauthorized(String),
|
||||
InternalServerError(String),
|
||||
Corrupted(String),
|
||||
FetchError(String),
|
||||
}
|
||||
|
||||
pub trait Page: Sized {
|
||||
type Id;
|
||||
|
||||
/// Gets the identifier of the page
|
||||
/// This can be used to differentiate between pages
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
fn id(&self) -> Self::Id;
|
||||
fn author(&self) -> String;
|
||||
fn routing(&self) -> PageRouting;
|
||||
/// Get the revision of the page
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `String` - The revision of the page - This is implementation defined
|
||||
fn version(&self) -> String;
|
||||
fn update(&mut self) -> Result<(), PageError>;
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PageRouting {
|
||||
pub hosts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub enum PageStatus {
|
||||
// 200
|
||||
Ok = 200,
|
||||
Created = 201,
|
||||
Accepted = 202,
|
||||
NoContent = 204,
|
||||
ResetContent = 205,
|
||||
|
||||
// 300
|
||||
|
||||
// 400
|
||||
BadRequest = 400,
|
||||
Unauthorized = 401,
|
||||
// No one cares about 402...
|
||||
Forbidden = 403,
|
||||
NotFound = 404
|
||||
}
|
||||
|
||||
pub struct PageQueryResult {
|
||||
pub content: Option<String>,
|
||||
pub status: PageStatus
|
||||
}
|
||||
|
||||
pub trait PageManager<'a, P: Page + 'a> {
|
||||
/// Resolve a page
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `author` - The author of the repository - This is required
|
||||
/// * `host` - The host of the repository - This allows CNAMEs to be used to point to the repository
|
||||
/// * `path` - The query path - This is treated either as a file path (in the case of a user page),
|
||||
/// or as a repository path (in the case of a project page)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `PageQueryResult` - The result of the query - This can be page contents, etc
|
||||
/// * `PageError` - Any error that occurred processing the query
|
||||
///
|
||||
/// Note that page errors, such as Error 404, are not an error that occurs processing the query
|
||||
/// Thus, they are returned via the `PageQueryResult` instead of the `PageError`
|
||||
fn query(&self, author: String, path: String, host: Option<String>) -> Result<PageQueryResult, PageError>;
|
||||
|
||||
fn page(&self, id: P::Id) -> Result<&P, PageError>;
|
||||
fn page_mut(&mut self, id: P::Id) -> Result<&mut P, PageError>;
|
||||
fn pages_iter(&'a self) -> impl Iterator<Item = &'a P>;
|
||||
/// Delete the page
|
||||
/// This will remove the page from being hosted or stored
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<(), (PageError, Self)>` - If the page was deleted successfully, this will return `Ok(())`
|
||||
/// Otherwise, it will return `Err((PageError, Self))` with the error and the page
|
||||
///
|
||||
/// Consequently, since the page is not returned if it is deleted successfully, the page is consumed
|
||||
/// And since it returns it if it fails, it is recoverable for failure handling
|
||||
fn delete(&mut self, id: P::Id) -> Result<(), PageError>;
|
||||
}
|
32
src/main.rs
32
src/main.rs
|
@ -1,6 +1,36 @@
|
|||
use conf::CONFIG;
|
||||
|
||||
pub mod backends;
|
||||
pub mod conf;
|
||||
pub mod sitedata;
|
||||
pub mod data;
|
||||
pub mod schema;
|
||||
pub mod models;
|
||||
|
||||
fn prepare_logger() {
|
||||
// Fern
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"{}[{}][{}] {}",
|
||||
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
|
||||
record.target(),
|
||||
record.level(),
|
||||
message
|
||||
))
|
||||
})
|
||||
.level(log::LevelFilter::Debug)
|
||||
.chain(std::io::stdout())
|
||||
.apply()
|
||||
.expect("Failed to initialize logger");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Prepare logger
|
||||
prepare_logger();
|
||||
|
||||
// Load configuration
|
||||
let config = CONFIG.clone();
|
||||
|
||||
// Print configuration
|
||||
println!("Configuration: {:#?}", config);
|
||||
}
|
50
src/models.rs
Normal file
50
src/models.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use diesel::prelude::{Insertable, Queryable};
|
||||
|
||||
use crate::schema::*;
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "pages"]
|
||||
pub struct NewPage {
|
||||
pub author: String,
|
||||
pub name: String,
|
||||
pub status: i32,
|
||||
}
|
||||
|
||||
#[derive(Queryable)]
|
||||
pub struct Page {
|
||||
pub id: i32,
|
||||
pub author: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "routing_record"]
|
||||
pub struct NewRoutingRecord {
|
||||
pub page_id: i32,
|
||||
pub record_type: String,
|
||||
pub record_value: String,
|
||||
}
|
||||
|
||||
#[derive(Queryable)]
|
||||
pub struct RoutingRecord {
|
||||
pub id: i32,
|
||||
pub page_id: i32,
|
||||
pub record_type: String,
|
||||
pub record_value: String,
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "git_page_source"]
|
||||
pub struct NewGitPageSource {
|
||||
pub page_id: i32,
|
||||
pub repo_url: String,
|
||||
pub branch: String,
|
||||
}
|
||||
|
||||
#[derive(Queryable)]
|
||||
pub struct GitPageSource {
|
||||
pub id: i32,
|
||||
pub page_id: i32,
|
||||
pub repo_url: String,
|
||||
pub branch: String,
|
||||
}
|
46
src/schema.rs
Normal file
46
src/schema.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Diesel schema
|
||||
diesel::table! {
|
||||
pages (id) {
|
||||
id -> Int4,
|
||||
author -> Text,
|
||||
name -> Text,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
// - 0: Invalid
|
||||
// - 1: Fetching
|
||||
// - 2: Validated
|
||||
// - 3: Ready
|
||||
status -> Integer
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
routing_record (id) {
|
||||
id -> Int4,
|
||||
page_id -> Int4,
|
||||
record_value -> Text,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
git_page_source (id) {
|
||||
id -> Int4,
|
||||
page_id -> Int4,
|
||||
repo_url -> Text,
|
||||
branch -> Text,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(routing_record -> pages (page_id));
|
||||
|
||||
diesel::joinable!(git_page_source -> pages (page_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
pages,
|
||||
routing_record,
|
||||
git_page_source,
|
||||
);
|
|
@ -1,17 +0,0 @@
|
|||
pub enum SiteError {
|
||||
PageNotFound(String),
|
||||
DataError(String),
|
||||
NetworkError(String)
|
||||
}
|
||||
|
||||
pub trait Site {
|
||||
fn get_page(&self, url: &str) -> Result<Vec<u8>, ()>;
|
||||
}
|
||||
|
||||
pub trait SiteControl<S: Site> {
|
||||
fn is_ok() -> bool;
|
||||
fn site(&self) -> S;
|
||||
fn can_update(&self) -> bool;
|
||||
fn repair(&mut self) -> Result<(), ()>;
|
||||
fn update(&mut self) -> Result<S, ()>;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
pub struct GitSiteProvider {
|
||||
pub current_commit: String
|
||||
}
|
||||
|
||||
pub impl GitSiteProvider {
|
||||
fn from_remote(url: &str) -> Self {
|
||||
|
||||
|
||||
Self {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub impl Site for GitSiteProvider {
|
||||
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
pub mod control;
|
||||
pub mod git;
|
Loading…
Add table
Reference in a new issue