Fixed syntax, fixed tests
This commit is contained in:
parent
4656288cf1
commit
a4bff93c86
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ target
|
|||||||
.idea
|
.idea
|
||||||
src/bin/sandbox.rs
|
src/bin/sandbox.rs
|
||||||
sandbox
|
sandbox
|
||||||
|
db/
|
||||||
204
Cargo.lock
generated
204
Cargo.lock
generated
@ -32,6 +32,17 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.88"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -107,6 +118,27 @@ dependencies = [
|
|||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.17.0"
|
version = "3.17.0"
|
||||||
@ -154,18 +186,65 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
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 = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-iterator"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -208,6 +287,16 @@ dependencies = [
|
|||||||
"pin-utils",
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
@ -216,9 +305,27 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashlink"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
@ -357,6 +464,16 @@ version = "0.2.171"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsqlite3-sys"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "947e6816f7825b2b45027c2c32e7085da9934defa535de4a6a46b10a4d5257fa"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
@ -447,6 +564,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.94"
|
version = "1.0.94"
|
||||||
@ -465,6 +588,20 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusqlite"
|
||||||
|
version = "0.35.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a22715a5d6deef63c637207afbe68d0c72c3f8d0022d7cf9714c442d6157606b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"fallible-iterator",
|
||||||
|
"fallible-streaming-iterator",
|
||||||
|
"hashlink",
|
||||||
|
"libsqlite3-sys",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
@ -546,6 +683,30 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha256"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"hex",
|
||||||
|
"sha2",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -592,6 +753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -613,9 +775,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.21"
|
version = "0.8.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231"
|
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
@ -634,9 +796,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.25"
|
version = "0.22.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485"
|
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
@ -648,9 +810,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_write"
|
name = "toml_write"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976"
|
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
@ -700,12 +862,30 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
@ -904,9 +1084,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.7"
|
version = "0.7.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
|
checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -916,8 +1096,12 @@ name = "yyyi_ru"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"mtgott",
|
"mtgott",
|
||||||
|
"rusqlite",
|
||||||
|
"serde",
|
||||||
|
"sha256",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -7,5 +7,9 @@ edition = "2024"
|
|||||||
axum = "0.8.3"
|
axum = "0.8.3"
|
||||||
tokio = { version = "1.44.1", features = ["rt-multi-thread"] }
|
tokio = { version = "1.44.1", features = ["rt-multi-thread"] }
|
||||||
mtgott = { path = "./mtgott" }
|
mtgott = { path = "./mtgott" }
|
||||||
toml="0.8.21"
|
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.40"
|
||||||
|
rusqlite = "0.35.0"
|
||||||
|
sha256 = "1.6.0"
|
||||||
|
toml = { version = "0.8.22" }
|
||||||
|
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||||
|
base64 = "0.22.1"
|
||||||
|
|||||||
13
assets/HypertextPages/login.mtgott.html
Normal file
13
assets/HypertextPages/login.mtgott.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{@ body $ @}
|
||||||
|
{%let pres = missing-text[$lang].index %}
|
||||||
|
<div class="main-container">
|
||||||
|
<form action="/login" method="POST">
|
||||||
|
<input type="hidden" name="csrf" value="{{$token}}">
|
||||||
|
<label>Username: <input name="username"></label><br>
|
||||||
|
<label>Password: <input name="password" type="password"></label><br>
|
||||||
|
<button>Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{%}
|
||||||
|
{@}
|
||||||
|
{$ main = d: base.main d.lang missing-text[d.lang].index.title (this.body d) $}
|
||||||
14
assets/initial_layout.toml
Normal file
14
assets/initial_layout.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[[users]]
|
||||||
|
name="Гриша"
|
||||||
|
role=0
|
||||||
|
|
||||||
|
[[users]]
|
||||||
|
name="Скибидист"
|
||||||
|
role=2
|
||||||
|
|
||||||
|
[[channels]]
|
||||||
|
# Ofcourse, this is a name for admin, names of channels on html pages CAN be translated
|
||||||
|
name="Блог"
|
||||||
|
|
||||||
|
[[channels]]
|
||||||
|
name="Содержательное"
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
index: {
|
|
||||||
title: "Gregory's title page",
|
|
||||||
about_me_header: "About me",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
index: {
|
|
||||||
title: "Гришина заглавная страничка",
|
|
||||||
about_me_header: "Обо мне",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -14,7 +14,11 @@ pub fn is_digit(ch: char) -> bool {
|
|||||||
|
|
||||||
pub fn is_normal_word_constituent(ch: char) -> bool {
|
pub fn is_normal_word_constituent(ch: char) -> bool {
|
||||||
('0'..='9').contains(&ch) || ('a'..='z').contains(&ch) || ('A'..='Z').contains(&ch)
|
('0'..='9').contains(&ch) || ('a'..='z').contains(&ch) || ('A'..='Z').contains(&ch)
|
||||||
|| "<>=-_+/|&~!^*".contains(ch)
|
|| "-_".contains(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_queer_word_constituent(ch: char) -> bool {
|
||||||
|
is_normal_word_constituent(ch) || "%<>=+/|&~!^*".contains(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_normal_word(s: &str) -> bool {
|
pub fn is_normal_word(s: &str) -> bool {
|
||||||
@ -26,6 +30,7 @@ pub fn escape_for_html(s: &str) -> String {
|
|||||||
.replace("'", "'").replace("\"", """)
|
.replace("'", "'").replace("\"", """)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use on normal words only
|
||||||
pub fn is_special_name(s: &str) -> bool {
|
pub fn is_special_name(s: &str) -> bool {
|
||||||
s.chars().any(|ch| "+'/|&~!^%*".contains(ch)) || s.ends_with("-") || s == "this"
|
s.chars().any(|ch| "+'/|&~!^%*".contains(ch)) || s.ends_with("-") || s == "this"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ use crate::charclasses::{is_special_name, is_digit, is_lnspace,
|
|||||||
is_normal_word_constituent, is_whitespace};
|
is_normal_word_constituent, is_whitespace};
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use charclasses::is_queer_word_constituent;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct NewLambdaExpression {
|
pub struct NewLambdaExpression {
|
||||||
@ -177,13 +178,20 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_word_ahead(&self) -> bool {
|
fn is_normal_word_ahead(&self) -> bool {
|
||||||
match self.here() {
|
match self.here() {
|
||||||
Some(ch) => is_normal_word_constituent(ch),
|
Some(ch) => is_normal_word_constituent(ch),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_queer_word_ahead(&self) -> bool {
|
||||||
|
match self.here() {
|
||||||
|
Some(ch) => is_queer_word_constituent(ch) && !self.is_ahead("%}"),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn advance(&mut self) {
|
fn advance(&mut self) {
|
||||||
self.p += self.text[self.p..].chars().next().unwrap().len_utf8();
|
self.p += self.text[self.p..].chars().next().unwrap().len_utf8();
|
||||||
}
|
}
|
||||||
@ -191,10 +199,8 @@ impl<'a> Parser<'a> {
|
|||||||
fn skip_whitespace(&mut self) {
|
fn skip_whitespace(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.here() {
|
match self.here() {
|
||||||
Some(ch ) => if !is_whitespace(ch) {
|
Some(ch ) if is_whitespace(ch) => self.advance(),
|
||||||
break
|
_ => break
|
||||||
} else { self.advance(); }
|
|
||||||
None => break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,10 +208,17 @@ impl<'a> Parser<'a> {
|
|||||||
fn skip_normal_word(&mut self){
|
fn skip_normal_word(&mut self){
|
||||||
loop {
|
loop {
|
||||||
match self.here() {
|
match self.here() {
|
||||||
Some(ch ) => if !is_normal_word_constituent(ch) {
|
Some(ch ) if is_normal_word_constituent(ch) => self.advance(),
|
||||||
break
|
_ => break
|
||||||
} else { self.advance(); }
|
}
|
||||||
None => break
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_queer_word(&mut self){
|
||||||
|
while !self.is_ahead("%}"){
|
||||||
|
match self.here() {
|
||||||
|
Some(ch ) if is_queer_word_constituent(ch) => self.advance(),
|
||||||
|
_ => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +310,7 @@ impl<'a> Parser<'a> {
|
|||||||
if self.is_char_ahead('$') {
|
if self.is_char_ahead('$') {
|
||||||
arg_names.push("$");
|
arg_names.push("$");
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
if self.is_word_ahead() {
|
if self.is_normal_word_ahead() {
|
||||||
return Err(FileParsingError::new(leave_space_between_dollar_argument_and_other_arguments,
|
return Err(FileParsingError::new(leave_space_between_dollar_argument_and_other_arguments,
|
||||||
self.p - 1, self.next_p()));
|
self.p - 1, self.next_p()));
|
||||||
}
|
}
|
||||||
@ -754,7 +767,7 @@ impl<'a> Parser<'a> {
|
|||||||
loop {
|
loop {
|
||||||
if self.is_digit_ahead() {
|
if self.is_digit_ahead() {
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
} else if self.is_word_ahead() {
|
} else if self.is_normal_word_ahead() {
|
||||||
return Err(self.new_unexpected_char_error(cant_start_word_immediately_after_digit))
|
return Err(self.new_unexpected_char_error(cant_start_word_immediately_after_digit))
|
||||||
} else {
|
} else {
|
||||||
return match self.text[p1..self.p].parse::<u64>() {
|
return match self.text[p1..self.p].parse::<u64>() {
|
||||||
@ -763,9 +776,9 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if self.is_word_ahead() {
|
} else if self.is_queer_word_ahead() {
|
||||||
let p1 = self.p;
|
let p1 = self.p;
|
||||||
self.skip_normal_word();
|
self.skip_queer_word();
|
||||||
let toplevel_name = &self.text[p1..self.p];
|
let toplevel_name = &self.text[p1..self.p];
|
||||||
let p2 = self.p;
|
let p2 = self.p;
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
@ -815,7 +828,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(n) => Expression::Local(n),
|
Some(n) => Expression::Local(n),
|
||||||
None => return Err(self.new_unexpected_char_error(cant_use_dollar_in_expression_of_element_without_dollar_argument)),
|
None => return Err(self.new_unexpected_char_error(cant_use_dollar_in_expression_of_element_without_dollar_argument)),
|
||||||
};
|
};
|
||||||
let bg: Expression = if self.is_word_ahead() {
|
let bg: Expression = if self.is_normal_word_ahead() {
|
||||||
let p1 = self.p;
|
let p1 = self.p;
|
||||||
self.skip_normal_word();
|
self.skip_normal_word();
|
||||||
let dollar_level_name = &self.text[p1..self.p];
|
let dollar_level_name = &self.text[p1..self.p];
|
||||||
|
|||||||
@ -172,6 +172,7 @@ pub fn add_entire_stdlib_to_root(root: &mut SharedValue) -> Result<(), Box<dyn E
|
|||||||
add_basic_bin_operator_to_root(root, "*", operator_product)?;
|
add_basic_bin_operator_to_root(root, "*", operator_product)?;
|
||||||
add_basic_bin_operator_to_root(root, "/", operator_division)?;
|
add_basic_bin_operator_to_root(root, "/", operator_division)?;
|
||||||
add_basic_bin_operator_to_root(root, "o/o", operator_remainder)?;
|
add_basic_bin_operator_to_root(root, "o/o", operator_remainder)?;
|
||||||
|
add_basic_bin_operator_to_root(root, "%", operator_remainder)?;
|
||||||
add_basic_bin_operator_to_root(root, "&&", operator_and)?;
|
add_basic_bin_operator_to_root(root, "&&", operator_and)?;
|
||||||
add_basic_bin_operator_to_root(root, "||", operator_or)?;
|
add_basic_bin_operator_to_root(root, "||", operator_or)?;
|
||||||
add_basic_bin_operator_to_root(root, "^^", operator_xor)?;
|
add_basic_bin_operator_to_root(root, "^^", operator_xor)?;
|
||||||
|
|||||||
@ -127,7 +127,7 @@ fn t010(){
|
|||||||
#[test]
|
#[test]
|
||||||
fn t011(){
|
fn t011(){
|
||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
FileWithPath{v_path: "file".into(), text: "{@el a @} {{a[1#}} {@} ".into()}
|
FileWithPath{v_path: "file".into(), text: "{@el a @} {{a[1]}} {@} ".into()}
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: "{#file.el $#}".into()}
|
FileWithPath{v_path: "index".into(), text: "{#file.el $#}".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
@ -142,7 +142,7 @@ fn t011(){
|
|||||||
#[test]
|
#[test]
|
||||||
fn t012(){
|
fn t012(){
|
||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
FileWithPath{v_path: "file".into(), text: "{@el a @} {{a[1#}} {@} ".into()}
|
FileWithPath{v_path: "file".into(), text: "{@el a @} {{a[1]}} {@} ".into()}
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: "{#file[\"el\"] $#}".into()}
|
FileWithPath{v_path: "index".into(), text: "{#file[\"el\"] $#}".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
@ -170,7 +170,7 @@ fn t013(){
|
|||||||
fn t014(){
|
fn t014(){
|
||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: " {{ $[0 #}} {{$ [1#}} {{$[ 2#}} ".into()}
|
FileWithPath{v_path: "index".into(), text: " {{ $[0 ]}} {{$ [1]}} {{$[ 2]}} ".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
let r = get_root_html_from_dir_text_html(i).unwrap();
|
let r = get_root_html_from_dir_text_html(i).unwrap();
|
||||||
assert_gave!(r.render(
|
assert_gave!(r.render(
|
||||||
@ -182,7 +182,7 @@ fn t014(){
|
|||||||
#[test]
|
#[test]
|
||||||
fn t015(){
|
fn t015(){
|
||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
FileWithPath{v_path: "help".into(), text: " {@www $ a b@} {{$[a#}} {{$[b#}} {@}".into()}
|
FileWithPath{v_path: "help".into(), text: " {@www $ a b@} {{$[a]}} {{$[b]}} {@}".into()}
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: " {#help.www $ 2 1 #}".into()}
|
FileWithPath{v_path: "index".into(), text: " {#help.www $ 2 1 #}".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
@ -242,7 +242,7 @@ fn t019(){
|
|||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
FileWithPath{v_path: "__".into(), text: "{$arr = [0, 10, 20, 30]$}".into()}
|
FileWithPath{v_path: "__".into(), text: "{$arr = [0, 10, 20, 30]$}".into()}
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: " {{ (x:y:z:w:w x z) 2 \"Lol\" __ x:z:z.arr[x#}}".into()}
|
FileWithPath{v_path: "index".into(), text: " {{ (x:y:z:w:w x z) 2 \"Lol\" __ x:z:z.arr[x]}}".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
let r = get_root_html_from_dir_text_html(i).unwrap();
|
let r = get_root_html_from_dir_text_html(i).unwrap();
|
||||||
assert_gave!(r.render(
|
assert_gave!(r.render(
|
||||||
@ -256,7 +256,7 @@ fn t020(){
|
|||||||
let i = MtgottDirContent{mtgott: vec![
|
let i = MtgottDirContent{mtgott: vec![
|
||||||
FileWithPath{v_path: "__".into(), text: "{$arr = [0, 10, 20, 30]$}".into()}
|
FileWithPath{v_path: "__".into(), text: "{$arr = [0, 10, 20, 30]$}".into()}
|
||||||
], imtgott: vec![
|
], imtgott: vec![
|
||||||
FileWithPath{v_path: "index".into(), text: " {{ (x:y:z:w:w x z) __ \"Lol\" 2 x:z:x.arr[z#}}".into()}
|
FileWithPath{v_path: "index".into(), text: " {{ (x:y:z:w:w x z) __ \"Lol\" 2 x:z:x.arr[z]}}".into()}
|
||||||
], plain: vec![]};
|
], plain: vec![]};
|
||||||
let r = get_root_html_from_dir_text_html(i).unwrap();
|
let r = get_root_html_from_dir_text_html(i).unwrap();
|
||||||
assert_gave!(r.render(
|
assert_gave!(r.render(
|
||||||
|
|||||||
6
src/bin/check.rs
Normal file
6
src/bin/check.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
extern crate yyyi_ru;
|
||||||
|
use yyyi_ru::database_operations::integrity_check;
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
integrity_check();
|
||||||
|
}
|
||||||
6
src/bin/initialize.rs
Normal file
6
src/bin/initialize.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
extern crate yyyi_ru;
|
||||||
|
use yyyi_ru::database_operations::initialization;
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
initialization();
|
||||||
|
}
|
||||||
227
src/database_operations.rs
Normal file
227
src/database_operations.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
use std::{fs, io};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use rusqlite::{Connection, Row, Rows, Statement};
|
||||||
|
use rusqlite::params;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs::metadata;
|
||||||
|
use std::io::Write;
|
||||||
|
use base64::Engine;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use base64::prelude::BASE64_STANDARD;
|
||||||
|
|
||||||
|
pub const INITIAL_LAYOUT_TOML: &str = "assets/initial_layout.toml";
|
||||||
|
pub const FILES_DIR: &str = "db/files";
|
||||||
|
pub const SQLITE_FILE: &str = "db/db.db";
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct InitialUser {
|
||||||
|
name: String,
|
||||||
|
role: i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct InitialChannel {
|
||||||
|
name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct InitialLayout {
|
||||||
|
users: Vec<InitialUser>,
|
||||||
|
channels: Vec<InitialChannel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! bail {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
eprintln!($($arg)*);
|
||||||
|
std::process::exit(1);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialization(){
|
||||||
|
let initial_layout_txt: String = match fs::read(INITIAL_LAYOUT_TOML) {
|
||||||
|
Ok(s) => String::from_utf8(s).expect("Need utf-8"),
|
||||||
|
Err(e) => bail!("Can't read {INITIAL_LAYOUT_TOML:?}: {e:?}")
|
||||||
|
};
|
||||||
|
let initial_layout: InitialLayout = toml::from_str(&initial_layout_txt)
|
||||||
|
.expect("Incorrect initialization layout");
|
||||||
|
|
||||||
|
if let Err(e) = fs::create_dir_all(&FILES_DIR) {
|
||||||
|
bail!("Failed to create directory {:?}: {}", &FILES_DIR, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
let connection: Connection = match Connection::open(&SQLITE_FILE) {
|
||||||
|
Ok(conn) => conn,
|
||||||
|
Err(e) => return bail!("Failed to open database {:?}: {}", &SQLITE_FILE, e)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schemas for database
|
||||||
|
let schemas = [
|
||||||
|
"CREATE TABLE IF NOT EXISTS `users` (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL,
|
||||||
|
password TEXT NOT NULL, role INTEGER NOT NULL);",
|
||||||
|
"CREATE TABLE IF NOT EXISTS `channels` (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL);",
|
||||||
|
"CREATE TABLE IF NOT EXISTS `messages` (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT NOT NULL,
|
||||||
|
user_id INTEGER NOT NULL, channel_id INTEGER NOT NULL, time TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES USERS(id),
|
||||||
|
FOREIGN KEY(channel_id) REFERENCES CHANNELS(id));",
|
||||||
|
"CREATE TABLE IF NOT EXISTS `files` (
|
||||||
|
storage_name TEXT PRIMARY KEY, name TEXT NOT NULL, content_type TEXT NOT NULL,
|
||||||
|
image_width INTEGER, image_height INTEGER);",
|
||||||
|
];
|
||||||
|
|
||||||
|
for sql in &schemas {
|
||||||
|
if let Err(e) = connection.execute(sql, params![]) {
|
||||||
|
return bail!("Failed to create table: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for user in initial_layout.users {
|
||||||
|
print!("Password for {}: ", user.name);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut password = String::new();
|
||||||
|
std::io::stdin().read_line(&mut password).expect("reading password");
|
||||||
|
print!("Repeat password for {}: ", user.name);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut repeat_password = String::new();
|
||||||
|
std::io::stdin().read_line(&mut repeat_password).expect("reading password");
|
||||||
|
if password != repeat_password {
|
||||||
|
panic!("Passwords do not match");
|
||||||
|
}
|
||||||
|
if password.len() < 4 {
|
||||||
|
panic!("Password too short")
|
||||||
|
}
|
||||||
|
let hash: String = sha256::digest(password);
|
||||||
|
connection.execute(
|
||||||
|
"INSERT INTO `users` (`name`, `password`, `role`) VALUES (?1, ?2, ?3)",
|
||||||
|
params![user.name, hash, user.role]
|
||||||
|
).expect("sql error");
|
||||||
|
}
|
||||||
|
|
||||||
|
for channel in initial_layout.channels {
|
||||||
|
connection.execute(
|
||||||
|
"INSERT INTO `channels` (`name`) VALUES (?1)",
|
||||||
|
(channel.name,)
|
||||||
|
).expect("sql error");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Initialization complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn integrity_check() {
|
||||||
|
// [ TEST ] Presence of directory files
|
||||||
|
if !Path::new(FILES_DIR).is_dir() {
|
||||||
|
return bail!("Directory {:?} is missing", &FILES_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ TEST ] can open database
|
||||||
|
let connection: Connection = match Connection::open(&SQLITE_FILE) {
|
||||||
|
Ok(conn) => conn,
|
||||||
|
Err(e) => bail!("Failed to open database {:?}: {}", &SQLITE_FILE, e)
|
||||||
|
};
|
||||||
|
|
||||||
|
// [ TEST ] Presence of tables USERS and CHANNELS
|
||||||
|
let mut stmt = connection.prepare("
|
||||||
|
SELECT 'users' AS name
|
||||||
|
UNION SELECT 'channels'
|
||||||
|
UNION SELECT 'messages'
|
||||||
|
UNION SELECT 'files'
|
||||||
|
EXCEPT
|
||||||
|
SELECT name FROM sqlite_master WHERE type = 'table'"
|
||||||
|
).expect("sql prepare");
|
||||||
|
let mut rows = stmt.query([]).expect("sql query");
|
||||||
|
let mut missing: Vec<String> = Vec::new();
|
||||||
|
while let Some(row) = rows.next().expect("Failed to read sql row") {
|
||||||
|
let name = row.get::<usize, String>(0).expect("Failed to read sql column");
|
||||||
|
missing.push(name);
|
||||||
|
}
|
||||||
|
if !missing.is_empty() {
|
||||||
|
bail!("Tables [{}] not present", missing.join(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. FILES entries vs directory database/files
|
||||||
|
// a) For each entry in FILES, file must exist
|
||||||
|
let mut stmt: Statement = connection.prepare(
|
||||||
|
"SELECT storage_name FROM `files`;"
|
||||||
|
).expect("sql prepare");
|
||||||
|
let mut rows = stmt.query([]).expect("sql query");
|
||||||
|
let mut db_files = Vec::new();
|
||||||
|
while let Some(row) = rows.next().expect("Reading sql row") {
|
||||||
|
let name = row.get::<usize, String>(0).expect("reading sql column");
|
||||||
|
db_files.push(name);
|
||||||
|
}
|
||||||
|
let mut missing_real_files: Vec<String> = Vec::new();
|
||||||
|
for storage_name in &db_files {
|
||||||
|
let path = PathBuf::from(FILES_DIR).join(storage_name);
|
||||||
|
if !path.is_file() {
|
||||||
|
missing_real_files.push(storage_name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// b) For each file in directory, entry must exist
|
||||||
|
let mut missing_db_file_entries: Vec<String> = Vec::new();
|
||||||
|
let entries = fs::read_dir(&FILES_DIR)
|
||||||
|
.expect(format!("Filed to open {FILES_DIR:?}").as_str());
|
||||||
|
let mut total_size_of_files: u64 = 0;
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry.expect("Failed to iterate over files in database/files");
|
||||||
|
let file_name: String = entry.file_name().to_str()
|
||||||
|
.expect("File name is not utf-8").to_string();
|
||||||
|
let metadata = metadata(PathBuf::from(FILES_DIR).join(&file_name)).expect("metadata");
|
||||||
|
if !metadata.is_file() {
|
||||||
|
bail!("Not a file: {:?}", file_name);
|
||||||
|
}
|
||||||
|
total_size_of_files += metadata.len();
|
||||||
|
if !db_files.contains(&file_name) {
|
||||||
|
missing_db_file_entries.push(file_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !missing_real_files.is_empty() || !missing_db_file_entries.is_empty() {
|
||||||
|
bail!("\
|
||||||
|
Mismatch between FILES table and files directory:
|
||||||
|
Missing real files (present according to FILES table):\n{}
|
||||||
|
Missing FILES table entries (present in real files directory):\n{}\n",
|
||||||
|
if missing_real_files.is_empty() { "No".to_string() } else { missing_real_files.join("\n") },
|
||||||
|
if missing_db_file_entries.is_empty() { "No".to_string() } else { missing_db_file_entries.join("\n") })
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Integrity OK");
|
||||||
|
// Integrity check complete. Collecting statistics
|
||||||
|
|
||||||
|
let msg_count: i64 = {
|
||||||
|
let mut stmt: Statement = connection.prepare(
|
||||||
|
"SELECT COUNT(*) FROM `messages`;"
|
||||||
|
).expect("sql prepare");
|
||||||
|
let mut rows: Rows = stmt.query([]).expect("sql query");
|
||||||
|
rows.next().expect("reading sql row").expect("sql error")
|
||||||
|
.get::<usize, i64>(0).expect("reading sql column")
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_count = db_files.len();
|
||||||
|
println!("Files count: {file_count}. Total weight of file storage: {total_size_of_files}");
|
||||||
|
println!("Messages count: {msg_count}");
|
||||||
|
|
||||||
|
println!("Users:");
|
||||||
|
let mut stmt: Statement = connection.prepare(
|
||||||
|
"SELECT id, name, role, password FROM `users`;").unwrap();
|
||||||
|
let mut rows: Rows = stmt.query([]).unwrap();
|
||||||
|
while let Some(row) = rows.next().unwrap() {
|
||||||
|
let id: i64 = row.get(0).unwrap();
|
||||||
|
let name: String = row.get(1).unwrap();
|
||||||
|
let role: i64 = row.get(2).unwrap();
|
||||||
|
let password: String = row.get(3).unwrap();
|
||||||
|
println!(" - {id}: {name} (role {role}) with password {password}");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Channels:");
|
||||||
|
let mut stmt = connection.prepare(
|
||||||
|
"SELECT id, name FROM `channels`;").unwrap();
|
||||||
|
let mut rows: Rows = stmt.query([]).unwrap();
|
||||||
|
while let Some(row) = rows.next().unwrap() {
|
||||||
|
let id: i64 = row.get(0).unwrap();
|
||||||
|
let name: String = row.get(1).unwrap();
|
||||||
|
println!(" - {id}: {name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/lib.rs
18
src/lib.rs
@ -1,16 +1,22 @@
|
|||||||
use axum;
|
pub mod database_operations;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use axum::http::HeaderValue;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use axum::http;
|
|
||||||
use mtgott::dirsearch::{search_dir, get_root_html};
|
use mtgott::dirsearch::{search_dir, get_root_html};
|
||||||
use mtgott::runtime::{MTGOTT, Value};
|
use mtgott::runtime::{MTGOTT, Value};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use axum;
|
||||||
|
use axum::http;
|
||||||
|
use axum::http::HeaderValue;
|
||||||
use axum::http::header::ACCEPT_LANGUAGE;
|
use axum::http::header::ACCEPT_LANGUAGE;
|
||||||
use std::rc::Rc;
|
use axum::extract::{Form, State};
|
||||||
|
use axum::response::{Html, IntoResponse, Redirect};
|
||||||
|
|
||||||
use chrono::{Datelike, TimeZone, Utc};
|
use chrono::{Datelike, TimeZone, Utc};
|
||||||
|
|
||||||
macro_rules! valarr {
|
macro_rules! valarr {
|
||||||
@ -155,16 +161,14 @@ pub async fn run_yyyi_ru() {
|
|||||||
|
|
||||||
let assets = Arc::new(AssetsCache::load_assets(&assets_dir).unwrap());
|
let assets = Arc::new(AssetsCache::load_assets(&assets_dir).unwrap());
|
||||||
|
|
||||||
// build our application with a single route
|
|
||||||
let app = axum::Router::new()
|
let app = axum::Router::new()
|
||||||
.without_v07_checks()
|
.without_v07_checks()
|
||||||
.route("/", axum::routing::MethodRouter::new().get(page_index))
|
.route("/", axum::routing::MethodRouter::new().get(page_index))
|
||||||
.route("/blog", axum::routing::get(page_blog))
|
.route("/blog", axum::routing::get(page_blog))
|
||||||
.route("/assets/{*path}", axum::routing::get(static_assets))
|
.route("/assets/{*path}", axum::routing::get(static_assets))
|
||||||
.fallback(fallback_page).with_state(assets);
|
.fallback(fallback_page).with_state(assets);
|
||||||
// .layer(axum::Extension(templates));
|
|
||||||
|
|
||||||
// run our app with hyper, listening globally on port 3000
|
// run our app with hyper
|
||||||
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
||||||
println!("Running on http://{address}");
|
println!("Running on http://{address}");
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user