implement list command
This commit is contained in:
parent
8309d26c9f
commit
3210581a22
7 changed files with 467 additions and 25 deletions
210
Cargo.lock
generated
210
Cargo.lock
generated
|
|
@ -391,9 +391,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.44"
|
version = "0.4.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|
@ -613,6 +613,40 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
|
||||||
|
dependencies = [
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.23.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "date_header"
|
name = "date_header"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
@ -690,6 +724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -788,6 +823,12 @@ dependencies = [
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519"
|
name = "ed25519"
|
||||||
version = "2.2.3"
|
version = "2.2.3"
|
||||||
|
|
@ -1135,6 +1176,20 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "grist-client"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "git+https://github.com/QazCetelic/grist-client-rs#a5e41d8a0debbb06bf2ff87c0a8aa80734251a32"
|
||||||
|
dependencies = [
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_repr",
|
||||||
|
"serde_with",
|
||||||
|
"url",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "growable-bloom-filter"
|
name = "growable-bloom-filter"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
|
|
@ -1159,13 +1214,19 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
|
|
@ -1226,6 +1287,12 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hkdf"
|
name = "hkdf"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
|
|
@ -1496,6 +1563,12 @@ version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -1571,6 +1644,17 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.14.0"
|
version = "2.14.0"
|
||||||
|
|
@ -1878,7 +1962,7 @@ dependencies = [
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"http",
|
"http",
|
||||||
"imbl",
|
"imbl",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"js_int",
|
"js_int",
|
||||||
"language-tags",
|
"language-tags",
|
||||||
|
|
@ -2141,6 +2225,16 @@ version = "0.1.54"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbf6f36070878c42c5233846cd3de24cf9016828fd47bc22957a687298bb21fc"
|
checksum = "cbf6f36070878c42c5233846cd3de24cf9016828fd47bc22957a687298bb21fc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
|
|
@ -2676,6 +2770,26 @@ dependencies = [
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast"
|
||||||
|
version = "1.0.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||||
|
dependencies = [
|
||||||
|
"ref-cast-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ref-cast-impl"
|
||||||
|
version = "1.0.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.12.3"
|
version = "1.12.3"
|
||||||
|
|
@ -2725,6 +2839,7 @@ dependencies = [
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
"mime_guess",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
|
@ -2832,7 +2947,7 @@ dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"getrandom 0.2.17",
|
"getrandom 0.2.17",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"js_int",
|
"js_int",
|
||||||
"konst",
|
"konst",
|
||||||
|
|
@ -2861,7 +2976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dbdeccb62cb4ffe3282325de8ba28cbc0fdce7c78a3f11b7241fbfdb9cb9907"
|
checksum = "2dbdeccb62cb4ffe3282325de8ba28cbc0fdce7c78a3f11b7241fbfdb9cb9907"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"as_variant",
|
"as_variant",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"js_int",
|
"js_int",
|
||||||
"js_option",
|
"js_option",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
|
@ -3044,6 +3159,30 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schemars"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
|
||||||
|
dependencies = [
|
||||||
|
"dyn-clone",
|
||||||
|
"ref-cast",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schemars"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
|
||||||
|
dependencies = [
|
||||||
|
"dyn-clone",
|
||||||
|
"ref-cast",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -3148,7 +3287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
|
checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
|
@ -3178,6 +3317,17 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_repr"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
@ -3199,6 +3349,38 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bs58",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"schemars 0.9.0",
|
||||||
|
"schemars 1.2.1",
|
||||||
|
"serde_core",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
|
|
@ -3235,10 +3417,12 @@ name = "shift_bot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"dirs",
|
"dirs",
|
||||||
"either",
|
"either",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"grist-client",
|
||||||
"log",
|
"log",
|
||||||
"matrix-sdk",
|
"matrix-sdk",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
|
|
@ -3666,7 +3850,7 @@ version = "0.25.11+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"toml_datetime 1.1.1+spec-1.1.0",
|
"toml_datetime 1.1.1+spec-1.1.0",
|
||||||
"toml_parser",
|
"toml_parser",
|
||||||
"winnow 1.0.3",
|
"winnow 1.0.3",
|
||||||
|
|
@ -4076,7 +4260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"wasm-encoder",
|
"wasm-encoder",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
@ -4120,7 +4304,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"hashbrown 0.15.5",
|
"hashbrown 0.15.5",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -4353,7 +4537,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"heck",
|
"heck",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
|
|
@ -4384,7 +4568,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
|
@ -4403,7 +4587,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"id-arena",
|
"id-arena",
|
||||||
"indexmap",
|
"indexmap 2.14.0",
|
||||||
"log",
|
"log",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,5 @@ log = "^0.4"
|
||||||
simple_logger = "^5.2"
|
simple_logger = "^5.2"
|
||||||
either = "^1.15"
|
either = "^1.15"
|
||||||
shlex = "2.0.1"
|
shlex = "2.0.1"
|
||||||
|
grist-client = { git = "https://github.com/QazCetelic/grist-client-rs", version = "0.0.1" }
|
||||||
|
chrono = "0.4.45"
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,12 @@ pub fn get_serve() -> Arc<Serve> {
|
||||||
pub struct Main {
|
pub struct Main {
|
||||||
/// The data directory.
|
/// The data directory.
|
||||||
static_dir: PathBuf,
|
static_dir: PathBuf,
|
||||||
|
/// Grist API KEY
|
||||||
|
grist_api_key: String,
|
||||||
}
|
}
|
||||||
impl Main {
|
impl Main {
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
pub fn new() -> Self {
|
pub fn new(grist_api_key: impl Into<String>) -> Self {
|
||||||
let static_dir_root = match dirs::data_dir().context("no `static_dir` directory found") {
|
let static_dir_root = match dirs::data_dir().context("no `static_dir` directory found") {
|
||||||
Ok(root) => root,
|
Ok(root) => root,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -77,6 +79,7 @@ impl Main {
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
static_dir: static_dir_root.join("shift_bot"),
|
static_dir: static_dir_root.join("shift_bot"),
|
||||||
|
grist_api_key: grist_api_key.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,11 +99,16 @@ impl Main {
|
||||||
pub fn session_file(&self) -> PathBuf {
|
pub fn session_file(&self) -> PathBuf {
|
||||||
self.from_static_dir(Self::SESSION_FILE_NAME)
|
self.from_static_dir(Self::SESSION_FILE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grist API KEY
|
||||||
|
pub fn grist_api_key(&self) -> &str {
|
||||||
|
&self.grist_api_key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Main {
|
impl Default for Main {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fmt::Write;
|
use crate::grist::Shift;
|
||||||
|
|
||||||
use clap::{CommandFactory, Parser, Subcommand};
|
use clap::{CommandFactory, Parser, Subcommand};
|
||||||
use matrix_sdk::{Client, Room};
|
use matrix_sdk::{Client, Room};
|
||||||
|
|
||||||
|
|
@ -27,19 +26,37 @@ enum Action {
|
||||||
Aide,
|
Aide,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a message to a room.
|
|
||||||
pub async fn send_room_msg(_client: Client, room: Room, content: String) -> Res<OwnedEventId> {
|
pub async fn send_room_msg(_client: Client, room: Room, content: String) -> Res<OwnedEventId> {
|
||||||
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
|
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
|
||||||
// let md_parser = pulldown_cmark::Parser::new(&content);
|
|
||||||
// let mut html_body = String::with_capacity(250);
|
|
||||||
// pulldown_cmark::html::push_html(&mut html_body, md_parser);
|
|
||||||
// let content = RoomMessageEventContent::text_html(content, html_body);
|
|
||||||
let content = RoomMessageEventContent::text_plain(content);
|
let content = RoomMessageEventContent::text_plain(content);
|
||||||
let sent = room.send(content).await?;
|
let sent = room.send(content).await?;
|
||||||
Ok(sent.event_id)
|
Ok(sent.event_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn handle(command: impl Into<String>) -> Res<()> {
|
pub async fn send_room_msg_html(
|
||||||
|
_client: Client,
|
||||||
|
room: Room,
|
||||||
|
html_body: String,
|
||||||
|
) -> Res<OwnedEventId> {
|
||||||
|
use matrix_sdk::ruma::events::room::message::RoomMessageEventContent;
|
||||||
|
// let md_parser = pulldown_cmark::Parser::new(&content);
|
||||||
|
// let mut html_body = String::with_capacity(250);
|
||||||
|
// pulldown_cmark::html::push_html(&mut html_body, md_parser);
|
||||||
|
let content = RoomMessageEventContent::text_html(html_body.clone(), html_body);
|
||||||
|
let sent = room.send(content).await?;
|
||||||
|
Ok(sent.event_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_shifts(shifts: Vec<Shift>) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
output.push_str("Shifts :\n<ul>");
|
||||||
|
for shift in shifts {
|
||||||
|
output.push_str(format!("<li>{}</li>", shift).as_ref());
|
||||||
|
}
|
||||||
|
output.push_str("</ul>");
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle(command: impl AsRef<str>, room: Room, client: Client) -> Res<()> {
|
pub async fn handle(command: impl AsRef<str>, room: Room, client: Client) -> Res<()> {
|
||||||
debug!("handling command: {}", command.as_ref());
|
debug!("handling command: {}", command.as_ref());
|
||||||
|
|
||||||
|
|
@ -50,6 +67,9 @@ pub async fn handle(command: impl AsRef<str>, room: Room, client: Client) -> Res
|
||||||
match clap.action {
|
match clap.action {
|
||||||
Action::Lister => {
|
Action::Lister => {
|
||||||
debug!("user asked for list");
|
debug!("user asked for list");
|
||||||
|
let shifts = crate::grist::list_shifts().await?;
|
||||||
|
debug!("{:?}", shifts);
|
||||||
|
send_room_msg_html(client, room, format_shifts(shifts)).await?;
|
||||||
}
|
}
|
||||||
Action::Ajouter { nom, infos } => {
|
Action::Ajouter { nom, infos } => {
|
||||||
debug!("user asked for add");
|
debug!("user asked for add");
|
||||||
|
|
|
||||||
220
src/grist.rs
Normal file
220
src/grist.rs
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
prelude! {}
|
||||||
|
|
||||||
|
use chrono::DateTime;
|
||||||
|
use grist_client::apis::configuration::Configuration;
|
||||||
|
use grist_client::apis::records_api::list_records;
|
||||||
|
use grist_client::models::{RecordsList, RecordsListRecordsInner};
|
||||||
|
|
||||||
|
pub const API_URL: &str = "https://grist.interhacker.space/api";
|
||||||
|
pub const SHIFTS_DOC: &str = "iwSaC82TsQiuD3MYSG9RXX";
|
||||||
|
pub const SHIFTS_TABLE: &str = "Shifts";
|
||||||
|
pub const SHIFT_TYPES_TABLE: &str = "Types_de_shifts";
|
||||||
|
pub const INSCRIPTIONS_TABLE: &str = "Inscriptions";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Priority {
|
||||||
|
Prioritaire,
|
||||||
|
Secondaire,
|
||||||
|
Bonus,
|
||||||
|
Urgent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Priority {
|
||||||
|
fn fmt(&self, f: &mut Fmt<'_>) -> FmtRes {
|
||||||
|
match self {
|
||||||
|
Priority::Prioritaire => write!(f, "<b>Prioritaire</b>"),
|
||||||
|
Priority::Secondaire => write!(f, "Secondaire"),
|
||||||
|
Priority::Bonus => write!(f, "Bonus"),
|
||||||
|
Priority::Urgent => write!(f, "<font color=\"red\">Prioritaire</font>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ShiftType {
|
||||||
|
pub name: String,
|
||||||
|
pub priority: Priority,
|
||||||
|
pub frequency: u64,
|
||||||
|
pub persons: u64,
|
||||||
|
pub duration: u64,
|
||||||
|
pub guide: String,
|
||||||
|
}
|
||||||
|
impl ShiftType {
|
||||||
|
pub fn new(
|
||||||
|
name: impl Into<String>,
|
||||||
|
priority: Priority,
|
||||||
|
frequency: u64,
|
||||||
|
persons: u64,
|
||||||
|
duration: u64,
|
||||||
|
guide: impl Into<String>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
priority: priority,
|
||||||
|
frequency: frequency,
|
||||||
|
persons: persons,
|
||||||
|
duration: duration,
|
||||||
|
guide: guide.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ShiftType {
|
||||||
|
fn fmt(&self, f: &mut Fmt<'_>) -> FmtRes {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} ({}): {} x/j, {} personnes, {} h",
|
||||||
|
self.name, self.priority, self.frequency, self.persons, self.duration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {"Autres_infos": Null, "Heure_de_debut": Number(1782144000), "Inscriptions": Array [String("L"), Number(1)], "Type_de_shift": Number(23)}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Shift {
|
||||||
|
pub shift_type: ShiftType,
|
||||||
|
pub start_time: u64,
|
||||||
|
pub inscriptions: Vec<String>,
|
||||||
|
}
|
||||||
|
impl Shift {
|
||||||
|
pub fn new(shift_type: ShiftType, start_time: u64, inscriptions: Vec<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
shift_type: shift_type,
|
||||||
|
start_time: start_time.into(),
|
||||||
|
inscriptions: inscriptions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Shift {
|
||||||
|
fn fmt(&self, f: &mut Fmt<'_>) -> FmtRes {
|
||||||
|
let start_time = DateTime::from_timestamp(self.start_time as i64, 0)
|
||||||
|
.expect("failed to parse timestamp")
|
||||||
|
.format("%H:%M");
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} ({}): à {}, durée {} h, inscrit·es : {}/{}",
|
||||||
|
self.shift_type.name,
|
||||||
|
self.shift_type.priority,
|
||||||
|
start_time,
|
||||||
|
self.shift_type.duration,
|
||||||
|
self.inscriptions.len(),
|
||||||
|
self.shift_type.persons
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_number(record: &RecordsListRecordsInner, column: &str) -> Res<u64> {
|
||||||
|
record
|
||||||
|
.fields
|
||||||
|
.get(column)
|
||||||
|
.ok_or(anyhow!("Failed to get column {}", column))?
|
||||||
|
.as_u64()
|
||||||
|
.ok_or(anyhow!("Failed to parse number"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_string(record: &RecordsListRecordsInner, column: &str) -> Res<String> {
|
||||||
|
record
|
||||||
|
.fields
|
||||||
|
.get(column)
|
||||||
|
.ok_or(anyhow!("Failed to get column {}", column))?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(anyhow!("Failed to parse number"))
|
||||||
|
.map(|s| s.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_priority(record: &RecordsListRecordsInner, column: &str) -> Res<Priority> {
|
||||||
|
match get_string(record, column)? {
|
||||||
|
s if s.starts_with("1") => Ok(Priority::Prioritaire),
|
||||||
|
s if s.starts_with("2") => Ok(Priority::Secondaire),
|
||||||
|
s if s.starts_with("3") => Ok(Priority::Bonus),
|
||||||
|
s if s.starts_with("0") => Ok(Priority::Urgent),
|
||||||
|
_ => Err(anyhow!("can't parse priority")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_number_array(record: RecordsListRecordsInner, column: &str) -> Res<Vec<u64>> {
|
||||||
|
let val_col = record
|
||||||
|
.fields
|
||||||
|
.get(column)
|
||||||
|
.ok_or(anyhow!("Failed to get column {}", column))?;
|
||||||
|
if val_col.is_null() {
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
let mut val_array = val_col
|
||||||
|
.as_array()
|
||||||
|
.ok_or(anyhow!("Failed to parse array"))?
|
||||||
|
.clone();
|
||||||
|
val_array.remove(0);
|
||||||
|
debug!("{:?}", val_array);
|
||||||
|
let mut u64_array = Vec::new();
|
||||||
|
for val in val_array {
|
||||||
|
let u = val.as_u64().ok_or(anyhow!("Failed to parse number"))?;
|
||||||
|
u64_array.push(u);
|
||||||
|
}
|
||||||
|
Ok(u64_array)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_records(doc: &str, table: &str) -> Res<RecordsList> {
|
||||||
|
let conf = conf::get();
|
||||||
|
let api_key = conf.grist_api_key();
|
||||||
|
let grist_conf = Configuration::new(API_URL.into(), Some(api_key.into()));
|
||||||
|
list_records(&grist_conf, doc, table, None, None, None, None, None, None)
|
||||||
|
.await
|
||||||
|
.context("Failed to list records")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_shift_type(index: u64) -> Res<ShiftType> {
|
||||||
|
let record_list = get_records(SHIFTS_DOC, SHIFT_TYPES_TABLE).await?;
|
||||||
|
let record = record_list
|
||||||
|
.records
|
||||||
|
.iter()
|
||||||
|
.find(|record| record.id == index)
|
||||||
|
.ok_or(anyhow!("can't find shift type"))?;
|
||||||
|
Ok(ShiftType::new(
|
||||||
|
get_string(&record, "Nom")?,
|
||||||
|
get_priority(&record, "Priorite")?,
|
||||||
|
get_number(&record, "Frequence_jour")?,
|
||||||
|
get_number(&record, "Personnes_shift")?,
|
||||||
|
get_number(&record, "Duree_h_")?,
|
||||||
|
get_string(&record, "Guide")?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_inscription(index: u64) -> Res<String> {
|
||||||
|
let record_list = get_records(SHIFTS_DOC, INSCRIPTIONS_TABLE).await?;
|
||||||
|
let record = record_list
|
||||||
|
.records
|
||||||
|
.iter()
|
||||||
|
.find(|record| record.id == index)
|
||||||
|
.ok_or(anyhow!("can't find inscription"))?
|
||||||
|
.clone();
|
||||||
|
let name = get_string(&record, "Personne")?.into();
|
||||||
|
Ok(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_shifts() -> Res<Vec<Shift>> {
|
||||||
|
let record_list = get_records(SHIFTS_DOC, SHIFTS_TABLE).await?;
|
||||||
|
debug!("{:?}", record_list);
|
||||||
|
let mut shifts: Vec<Shift> = Vec::new();
|
||||||
|
for record in record_list.records {
|
||||||
|
let shift_type_ref =
|
||||||
|
get_number(&record, "Type_de_shift").context("getting shift type ref")?;
|
||||||
|
let shift_type = get_shift_type(shift_type_ref).await?;
|
||||||
|
let start_time = get_number(&record, "Heure_de_debut")?;
|
||||||
|
let inscriptions_refs =
|
||||||
|
get_number_array(record, "Inscriptions").context("getting inscriptions refs")?;
|
||||||
|
// let inscriptions = inscriptions_refs
|
||||||
|
// .iter()
|
||||||
|
// .filter_map(async |i| get_inscription(i).await.ok())
|
||||||
|
// .collect();
|
||||||
|
let mut inscriptions = Vec::new();
|
||||||
|
for inscription_ref in inscriptions_refs {
|
||||||
|
inscriptions.push(get_inscription(inscription_ref).await?);
|
||||||
|
}
|
||||||
|
let shift = Shift::new(shift_type, start_time, inscriptions);
|
||||||
|
shifts.push(shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(shifts)
|
||||||
|
}
|
||||||
|
|
@ -41,6 +41,8 @@ pub mod serve;
|
||||||
|
|
||||||
pub mod command;
|
pub mod command;
|
||||||
|
|
||||||
|
pub mod grist;
|
||||||
|
|
||||||
prelude! {}
|
prelude! {}
|
||||||
|
|
||||||
/// Warmup, runs before anything.
|
/// Warmup, runs before anything.
|
||||||
|
|
|
||||||
10
src/main.rs
10
src/main.rs
|
|
@ -13,7 +13,7 @@ WARNING: The contents of this file may NOT be used to train AI/LLM models. See N
|
||||||
details.
|
details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use clap::{Parser};
|
use clap::Parser;
|
||||||
|
|
||||||
use shift_bot::*;
|
use shift_bot::*;
|
||||||
|
|
||||||
|
|
@ -39,6 +39,7 @@ struct Clap {
|
||||||
default_value = "shift_bot_dev"
|
default_value = "shift_bot_dev"
|
||||||
)]
|
)]
|
||||||
username: String,
|
username: String,
|
||||||
|
|
||||||
/// Homeserver.
|
/// Homeserver.
|
||||||
#[arg(
|
#[arg(
|
||||||
short = 's',
|
short = 's',
|
||||||
|
|
@ -47,9 +48,14 @@ struct Clap {
|
||||||
default_value = "matrix.org"
|
default_value = "matrix.org"
|
||||||
)]
|
)]
|
||||||
homeserver: String,
|
homeserver: String,
|
||||||
|
|
||||||
/// Password of the element bot account.
|
/// Password of the element bot account.
|
||||||
#[arg(short, long, value_name = "PASSWORD")]
|
#[arg(short, long, value_name = "PASSWORD")]
|
||||||
password: String,
|
password: String,
|
||||||
|
|
||||||
|
/// Grist API KEY
|
||||||
|
#[arg(short, long)]
|
||||||
|
grist_api_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clap {
|
impl Clap {
|
||||||
|
|
@ -69,7 +75,7 @@ impl Clap {
|
||||||
async fn run(self) -> Res<()> {
|
async fn run(self) -> Res<()> {
|
||||||
simple_logger::init_with_level(self.verb_level())
|
simple_logger::init_with_level(self.verb_level())
|
||||||
.context("something when wrong while initializing logger")?;
|
.context("something when wrong while initializing logger")?;
|
||||||
conf::set(conf::Main::new());
|
conf::set(conf::Main::new(self.grist_api_key));
|
||||||
warmup(self.wipe)?;
|
warmup(self.wipe)?;
|
||||||
let bot = MatrixId::new(self.username, self.homeserver);
|
let bot = MatrixId::new(self.username, self.homeserver);
|
||||||
let conf = conf::Serve::new(bot, self.password);
|
let conf = conf::Serve::new(bot, self.password);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue