Add temporary CSV parsing import command
This commit is contained in:
parent
4c76734032
commit
f201329441
|
@ -2,12 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.58"
|
version = "1.0.58"
|
||||||
|
@ -43,6 +37,18 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.10.0"
|
version = "3.10.0"
|
||||||
|
@ -87,12 +93,6 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chunked_transfer"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ci_info"
|
name = "ci_info"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
@ -145,10 +145,12 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"csv",
|
||||||
"directories",
|
"directories",
|
||||||
"minicaldav",
|
"ics",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rusty-hook",
|
"rusty-hook",
|
||||||
|
"rustydav",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -173,12 +175,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "csv"
|
||||||
version = "1.3.2"
|
version = "1.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"bstr",
|
||||||
|
"csv-core",
|
||||||
|
"itoa 0.4.8",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -264,16 +279,6 @@ dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flate2"
|
|
||||||
version = "1.0.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
|
||||||
dependencies = [
|
|
||||||
"crc32fast",
|
|
||||||
"miniz_oxide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -421,7 +426,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -462,7 +467,7 @@ dependencies = [
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -484,6 +489,12 @@ dependencies = [
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ics"
|
||||||
|
version = "0.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b891481ef6353e3b97118d4650469e379a39e4373a66908c12f99763182826b1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -526,6 +537,12 @@ version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
|
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -600,28 +617,6 @@ version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minicaldav"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fb263a7d12c40d5f200dda93b3665b9ae714d4fe64a6467938c92d974a579edb"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"log",
|
|
||||||
"ureq",
|
|
||||||
"url",
|
|
||||||
"xmltree",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -893,6 +888,12 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
|
@ -939,33 +940,6 @@ dependencies = [
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ring"
|
|
||||||
version = "0.16.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
"spin",
|
|
||||||
"untrusted",
|
|
||||||
"web-sys",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls"
|
|
||||||
version = "0.20.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"ring",
|
|
||||||
"sct",
|
|
||||||
"webpki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusty-hook"
|
name = "rusty-hook"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
@ -978,6 +952,15 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustydav"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc4c86c47126ac8bfc573084610e93f4ca8726f3ae7bf6c64bd60476731b6e42"
|
||||||
|
dependencies = [
|
||||||
|
"reqwest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
|
@ -1003,16 +986,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sct"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
|
||||||
dependencies = [
|
|
||||||
"ring",
|
|
||||||
"untrusted",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
|
@ -1062,7 +1035,7 @@ version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -1074,7 +1047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"itoa",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -1095,12 +1068,6 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -1314,30 +1281,6 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "untrusted"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ureq"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"chunked_transfer",
|
|
||||||
"encoding_rs",
|
|
||||||
"flate2",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"rustls",
|
|
||||||
"url",
|
|
||||||
"webpki",
|
|
||||||
"webpki-roots",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
|
@ -1479,25 +1422,6 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "webpki"
|
|
||||||
version = "0.22.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
|
||||||
dependencies = [
|
|
||||||
"ring",
|
|
||||||
"untrusted",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "webpki-roots"
|
|
||||||
version = "0.22.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44d8de8415c823c8abd270ad483c6feeac771fad964890779f9a8cb24fbbc1bf"
|
|
||||||
dependencies = [
|
|
||||||
"webpki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -1586,18 +1510,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xml-rs"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xmltree"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
|
|
||||||
dependencies = [
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -26,6 +26,9 @@ version = "0.13"
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
|
||||||
|
[dependencies.csv]
|
||||||
|
version = "1.1"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "3.2"
|
version = "3.2"
|
||||||
features = ["cargo"]
|
features = ["cargo"]
|
||||||
|
@ -33,13 +36,16 @@ features = ["cargo"]
|
||||||
[dependencies.directories]
|
[dependencies.directories]
|
||||||
version = "4.0"
|
version = "4.0"
|
||||||
|
|
||||||
[dependencies.minicaldav]
|
[dependencies.ics]
|
||||||
version = "0.2"
|
version = "0.5"
|
||||||
|
|
||||||
[dependencies.reqwest]
|
[dependencies.reqwest]
|
||||||
version = "0.11"
|
version = "0.11"
|
||||||
features = ["json", "blocking"]
|
features = ["json", "blocking"]
|
||||||
|
|
||||||
|
[dependencies.rustydav]
|
||||||
|
version = "0.1"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
features = ["derive"]
|
features = ["derive"]
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use {
|
||||||
|
crate::config::Config, crate::constants, anyhow::anyhow,
|
||||||
|
base64::write::EncoderWriter as Base64Encoder, reqwest::Url, std::io::Write,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ApiClient {
|
||||||
|
pub base_url: Url,
|
||||||
|
pub client: reqwest::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiClient {
|
||||||
|
pub fn new(server_name: &str, configuration: &Config) -> anyhow::Result<Self> {
|
||||||
|
let server = configuration
|
||||||
|
.credentials
|
||||||
|
.servers
|
||||||
|
.get(server_name)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow!(
|
||||||
|
"Unknown server {}. Did you use '{} init' first? Known servers: {:#?}",
|
||||||
|
server_name,
|
||||||
|
env!("CARGO_BIN_NAME"),
|
||||||
|
configuration.credentials.servers.keys().collect::<Vec<_>>()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
use reqwest::header;
|
||||||
|
let mut default_headers = header::HeaderMap::new();
|
||||||
|
let mut auth_header = b"Basic ".to_vec();
|
||||||
|
{
|
||||||
|
let mut encoder = Base64Encoder::new(&mut auth_header, base64::STANDARD);
|
||||||
|
write!(encoder, "{}:{}", server.login_name, server.password).unwrap();
|
||||||
|
}
|
||||||
|
let mut auth_header = header::HeaderValue::from_bytes(&auth_header)?;
|
||||||
|
auth_header.set_sensitive(true);
|
||||||
|
default_headers.insert(header::AUTHORIZATION, auth_header);
|
||||||
|
|
||||||
|
let client = reqwest::Client::builder()
|
||||||
|
.user_agent(constants::USER_AGENT)
|
||||||
|
.default_headers(default_headers)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
Ok(ApiClient {
|
||||||
|
base_url: Url::parse(&server.url)?,
|
||||||
|
client: client,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
175
src/main.rs
175
src/main.rs
|
@ -1,51 +1,20 @@
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
mod api_client;
|
||||||
mod config;
|
mod config;
|
||||||
mod constants;
|
mod constants;
|
||||||
|
mod recipe;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
self::config::Config,
|
crate::api_client::ApiClient,
|
||||||
anyhow::anyhow,
|
crate::config::Config,
|
||||||
base64::write::EncoderWriter as Base64Encoder,
|
crate::recipe::Recipe,
|
||||||
chrono::{DateTime, Utc},
|
|
||||||
clap::{arg, command, ArgMatches, Command},
|
clap::{arg, command, ArgMatches, Command},
|
||||||
reqwest::Url,
|
reqwest::{StatusCode, Url},
|
||||||
std::io::Write,
|
std::path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_args() -> ArgMatches {
|
|
||||||
let server_arg = arg!(-s --server <server> "NextCloud server to connect to").required(false);
|
|
||||||
|
|
||||||
command!()
|
|
||||||
.propagate_version(true)
|
|
||||||
.subcommand_required(true)
|
|
||||||
.arg_required_else_help(true)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("init")
|
|
||||||
.about("Authenticate against the provided NextCloud server")
|
|
||||||
.arg(arg!(<server> "NextCloud server to connect to")),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("import")
|
|
||||||
.about("Import the given URLs into NextCloud's cookbook")
|
|
||||||
.arg(server_arg.clone())
|
|
||||||
.arg(arg!(<url> ... "One or more URLs each pointing to page with a recipe to import in NextCloud")),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
Command::new("schedule")
|
|
||||||
.about("")
|
|
||||||
.arg(server_arg.clone())
|
|
||||||
.arg(arg!(-d --days <days> "")
|
|
||||||
.value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..))
|
|
||||||
.required(false)
|
|
||||||
.default_value("7"))
|
|
||||||
)
|
|
||||||
.get_matches()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main(flavor = "multi_thread")]
|
#[tokio::main(flavor = "multi_thread")]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
let args = parse_args();
|
let args = parse_args();
|
||||||
|
@ -79,6 +48,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
println!("{:#?}", response); // TODO
|
println!("{:#?}", response); // TODO
|
||||||
|
assert!([StatusCode::OK, StatusCode::CONFLICT].contains(&response.status()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(("schedule", sub_matches)) => {
|
Some(("schedule", sub_matches)) => {
|
||||||
|
@ -90,21 +60,89 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.await?;
|
.await?;
|
||||||
println!("{:#?}", recipes.json::<Vec<Recipe>>().await?); // TODO
|
println!("{:#?}", recipes.json::<Vec<Recipe>>().await?); // TODO
|
||||||
}
|
}
|
||||||
|
Some(("schedule-csv", sub_matches)) => {
|
||||||
|
let csv_file = sub_matches
|
||||||
|
.get_one::<PathBuf>("csv_file")
|
||||||
|
.expect("<csv_file> is a mandatory parameter, it cannot be missing");
|
||||||
|
let calendar_name = sub_matches
|
||||||
|
.get_one::<String>("calendar_name")
|
||||||
|
.expect("<calendar_name> is a mandatory parameter, it cannot be missing");
|
||||||
|
|
||||||
|
let mut csv = csv::Reader::from_path(csv_file)?;
|
||||||
|
|
||||||
|
#[derive(serde::Deserialize)]
|
||||||
|
struct CsvRecord {
|
||||||
|
day: chrono::naive::NaiveDate,
|
||||||
|
lunch: String,
|
||||||
|
dinner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let recipe_urls = csv.deserialize::<CsvRecord>().fold(
|
||||||
|
std::collections::HashSet::new(),
|
||||||
|
|mut set, r| {
|
||||||
|
if let Ok(r) = r {
|
||||||
|
set.insert(r.lunch);
|
||||||
|
set.insert(r.dinner);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let api_client = get_api_client(&sub_matches, &configuration)?;
|
||||||
|
for url in recipe_urls {
|
||||||
|
let response = api_client
|
||||||
|
.client
|
||||||
|
.post(api_client.base_url.join("apps/cookbook/import")?)
|
||||||
|
.json(&serde_json::json!({
|
||||||
|
"url": url,
|
||||||
|
}))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
println!("{:#?}", response); // TODO
|
||||||
|
assert!([StatusCode::OK, StatusCode::CONFLICT].contains(&response.status()));
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
fn parse_args() -> ArgMatches {
|
||||||
#[serde(rename_all = "camelCase")]
|
let server_arg = arg!(-s --server <server> "NextCloud server to connect to").required(false);
|
||||||
struct Recipe {
|
|
||||||
#[serde(rename = "recipe_id")]
|
command!()
|
||||||
recipe_id: u32,
|
.propagate_version(true)
|
||||||
name: String,
|
.subcommand_required(true)
|
||||||
keywords: String,
|
.arg_required_else_help(true)
|
||||||
date_created: DateTime<Utc>,
|
.subcommand(
|
||||||
date_modified: DateTime<Utc>,
|
Command::new("init")
|
||||||
|
.about("Authenticate against the provided NextCloud server")
|
||||||
|
.arg(arg!(<server> "NextCloud server to connect to")),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("import")
|
||||||
|
.about("Import the given URLs into NextCloud's cookbook")
|
||||||
|
.arg(server_arg.clone())
|
||||||
|
.arg(arg!(<url> ... "One or more URLs each pointing to page with a recipe to import in NextCloud")),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("schedule")
|
||||||
|
.about("")
|
||||||
|
.arg(server_arg.clone())
|
||||||
|
.arg(arg!(-d --days <days> "")
|
||||||
|
.value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..))
|
||||||
|
.required(false)
|
||||||
|
.default_value("7"))
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
Command::new("schedule-csv")
|
||||||
|
.about("TEMPORARY WIP FUNCTION, UNSTABLE")
|
||||||
|
.arg(server_arg.clone())
|
||||||
|
.arg(arg!(<calendar_name> ""))
|
||||||
|
.arg(arg!(<csv_file> "").value_parser(clap::value_parser!(PathBuf)))
|
||||||
|
)
|
||||||
|
.get_matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_api_client(sub_matches: &ArgMatches, configuration: &Config) -> anyhow::Result<ApiClient> {
|
fn get_api_client(sub_matches: &ArgMatches, configuration: &Config) -> anyhow::Result<ApiClient> {
|
||||||
|
@ -121,46 +159,3 @@ fn get_api_client(sub_matches: &ArgMatches, configuration: &Config) -> anyhow::R
|
||||||
|
|
||||||
ApiClient::new(&server_name, &configuration)
|
ApiClient::new(&server_name, &configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ApiClient {
|
|
||||||
pub base_url: Url,
|
|
||||||
pub client: reqwest::Client,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ApiClient {
|
|
||||||
pub fn new(server_name: &str, configuration: &Config) -> anyhow::Result<Self> {
|
|
||||||
let server = configuration
|
|
||||||
.credentials
|
|
||||||
.servers
|
|
||||||
.get(server_name)
|
|
||||||
.ok_or_else(|| {
|
|
||||||
anyhow!(
|
|
||||||
"Unknown server {}. Did you use '{} init' first? Known servers: {:#?}",
|
|
||||||
server_name,
|
|
||||||
env!("CARGO_BIN_NAME"),
|
|
||||||
configuration.credentials.servers.keys().collect::<Vec<_>>()
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
use reqwest::header;
|
|
||||||
let mut default_headers = header::HeaderMap::new();
|
|
||||||
let mut auth_header = b"Basic ".to_vec();
|
|
||||||
{
|
|
||||||
let mut encoder = Base64Encoder::new(&mut auth_header, base64::STANDARD);
|
|
||||||
write!(encoder, "{}:{}", server.login_name, server.password).unwrap();
|
|
||||||
}
|
|
||||||
let mut auth_header = header::HeaderValue::from_bytes(&auth_header)?;
|
|
||||||
auth_header.set_sensitive(true);
|
|
||||||
default_headers.insert(header::AUTHORIZATION, auth_header);
|
|
||||||
|
|
||||||
let client = reqwest::Client::builder()
|
|
||||||
.user_agent(constants::USER_AGENT)
|
|
||||||
.default_headers(default_headers)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
Ok(ApiClient {
|
|
||||||
base_url: Url::parse(&server.url)?,
|
|
||||||
client: client,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use {
|
||||||
|
chrono::{DateTime, Utc},
|
||||||
|
serde::Deserialize,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Recipe {
|
||||||
|
#[serde(rename = "recipe_id")]
|
||||||
|
recipe_id: u32,
|
||||||
|
name: String,
|
||||||
|
keywords: String,
|
||||||
|
date_created: DateTime<Utc>,
|
||||||
|
date_modified: DateTime<Utc>,
|
||||||
|
}
|
Loading…
Reference in New Issue