Merge branch 'grocery-list' into 'master'
Collect relevant ingredients for grocery list Closes #3 See merge request nextcloud/cooking-schedule!2
This commit is contained in:
commit
e3d99c89e4
|
@ -3,6 +3,7 @@
|
|||
|
||||
stages:
|
||||
- build
|
||||
- check
|
||||
- test
|
||||
- deploy
|
||||
|
||||
|
@ -12,25 +13,6 @@ stages:
|
|||
- job: docker:build
|
||||
optional: true
|
||||
|
||||
.cargo_test_template:
|
||||
extends: .with_rust_image
|
||||
stage: test
|
||||
artifacts:
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: cobertura.xml
|
||||
junit: junit.xml
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_COMMON_ARGS: --workspace --no-default-features
|
||||
script:
|
||||
- mkdir -p .git/hooks # for cargo-husky
|
||||
- cargo tarpaulin ${CARGO_COMMON_ARGS} --locked -o Xml
|
||||
- cargo test ${CARGO_COMMON_ARGS} -- -Z unstable-options --format json | tee test-results.json
|
||||
- cargo2junit < test-results.json > junit.xml
|
||||
# - cargo bench ${CARGO_COMMON_ARGS} # DISABLED UNTIL WE HAVE BENCH TESTS
|
||||
|
||||
docker:build:
|
||||
stage: build
|
||||
variables:
|
||||
|
@ -49,8 +31,34 @@ docker:build:
|
|||
- Dockerfile
|
||||
allow_failure: true
|
||||
|
||||
cargo:check:
|
||||
extends: .with_rust_image
|
||||
stage: check
|
||||
variables:
|
||||
CARGO_COMMON_ARGS: --workspace --no-default-features
|
||||
script:
|
||||
- reuse lint
|
||||
- cargo fmt -- --check
|
||||
- cargo deny check
|
||||
|
||||
cargo:test:
|
||||
extends: .cargo_test_template
|
||||
extends: .with_rust_image
|
||||
stage: test
|
||||
artifacts:
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: cobertura.xml
|
||||
junit: junit.xml
|
||||
variables:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_COMMON_ARGS: --workspace --no-default-features
|
||||
script:
|
||||
- mkdir -p .git/hooks # for rusty-hook
|
||||
- cargo tarpaulin ${CARGO_COMMON_ARGS} --locked -o Xml
|
||||
- cargo test ${CARGO_COMMON_ARGS} -- -Z unstable-options --format json | tee test-results.json
|
||||
- cargo2junit < test-results.json > junit.xml
|
||||
# - cargo bench ${CARGO_COMMON_ARGS} # DISABLED UNTIL WE HAVE BENCH TESTS
|
||||
|
||||
cargo:doc: # pages: in the future
|
||||
extends: .with_rust_image
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
[hooks]
|
||||
pre-commit = "reuse lint && cargo fmt -- --check && cargo test"
|
||||
pre-commit = "reuse lint && cargo deny check && cargo fmt -- --check && cargo test"
|
||||
pre-push = "cargo check"
|
|
@ -6,7 +6,28 @@
|
|||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'cook'",
|
||||
"name": "Debug executable 'cook' -> groceries",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=cook",
|
||||
"--package=cooking-schedule"
|
||||
],
|
||||
"filter": {
|
||||
"name": "cook",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": ["groceries", "Cucina"],
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceFolder}",
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'cook' -> schedule-csv",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
|
@ -19,6 +40,30 @@
|
|||
}
|
||||
},
|
||||
"args": ["schedule-csv", "Cucina", "examples/example-schedule.csv"],
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'cook' -> purge",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=cook",
|
||||
"--package=cooking-schedule"
|
||||
],
|
||||
"filter": {
|
||||
"name": "cook",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": ["purge", "Cucina"],
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
|
@ -38,6 +83,9 @@
|
|||
}
|
||||
},
|
||||
"args": [],
|
||||
"env": {
|
||||
"RUST_LOG": "debug",
|
||||
},
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -3,18 +3,12 @@
|
|||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -72,9 +66,9 @@ checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
|
@ -108,12 +102,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chunked_transfer"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||
|
||||
[[package]]
|
||||
name = "ci_info"
|
||||
version = "0.10.2"
|
||||
|
@ -125,9 +113,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.8"
|
||||
version = "3.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
|
@ -168,10 +156,12 @@ dependencies = [
|
|||
"clap",
|
||||
"csv",
|
||||
"directories",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"iana-time-zone",
|
||||
"ics",
|
||||
"minicaldav",
|
||||
"icalendar",
|
||||
"libxml",
|
||||
"log",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"rusty-hook",
|
||||
"serde",
|
||||
|
@ -180,7 +170,6 @@ dependencies = [
|
|||
"strum_macros",
|
||||
"tokio",
|
||||
"toml",
|
||||
"ureq",
|
||||
"webbrowser",
|
||||
]
|
||||
|
||||
|
@ -200,15 +189,6 @@ version = "0.8.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.6"
|
||||
|
@ -295,6 +275,19 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "envmnt"
|
||||
version = "0.8.4"
|
||||
|
@ -307,23 +300,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -491,9 +474,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.1"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -545,10 +528,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.19"
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
|
@ -582,24 +571,16 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.40"
|
||||
name = "icalendar"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00c0d80ad9ca8d30ca648bf6cb1e3e3326d75071b76dbe143dd4a9cedcd58975"
|
||||
checksum = "bf4c8ac7e9b7eefe850f6380c68ef5fd1300858c1ef65d121d602a9bab63c2f4"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
"chrono",
|
||||
"nom",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ics"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b891481ef6353e3b97118d4650469e379a39e4373a66908c12f99763182826b1"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -676,9 +657,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.58"
|
||||
version = "0.3.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
|
||||
checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -695,6 +676,17 @@ version = "0.2.126"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "libxml"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "687f5a78939052c5d02865c0fe3ea2ce2acdca875f7f81db82f7aef256dd97ac"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
|
@ -723,26 +715,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "minicaldav"
|
||||
version = "0.2.0"
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
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",
|
||||
]
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
|
@ -836,6 +812,16 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
|
@ -888,15 +874,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.40"
|
||||
version = "0.10.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e"
|
||||
checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
|
@ -926,9 +912,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.74"
|
||||
version = "0.9.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1"
|
||||
checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
|
@ -939,9 +925,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
|
@ -979,9 +965,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.40"
|
||||
version = "1.0.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -997,9 +983,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
@ -1015,12 +1001,29 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
|
@ -1067,33 +1070,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustversion"
|
||||
version = "1.0.8"
|
||||
|
@ -1137,16 +1113,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "security-framework"
|
||||
version = "2.6.1"
|
||||
|
@ -1172,18 +1138,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1215,9 +1181,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
|
||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -1239,12 +1208,6 @@ dependencies = [
|
|||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
@ -1361,10 +1324,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.19.2"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
||||
checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
|
@ -1429,9 +1393,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
|||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.35"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
|
||||
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
|
@ -1440,9 +1404,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.28"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
|
||||
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
@ -1461,9 +1425,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
@ -1480,30 +1444,6 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chunked_transfer",
|
||||
"encoding_rs",
|
||||
"flate2",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls",
|
||||
"url",
|
||||
"webpki",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
|
@ -1516,6 +1456,15 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
@ -1557,9 +1506,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.81"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1567,13 +1516,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.81"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
|
@ -1582,9 +1531,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.31"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f"
|
||||
checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
|
@ -1594,9 +1543,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1604,9 +1553,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.81"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1617,15 +1566,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.81"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.58"
|
||||
version = "0.3.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
|
||||
checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -1645,25 +1594,6 @@ dependencies = [
|
|||
"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.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.5.1"
|
||||
|
@ -1752,18 +1682,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
|||
dependencies = [
|
||||
"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",
|
||||
]
|
||||
|
|
27
Cargo.toml
27
Cargo.toml
|
@ -24,10 +24,8 @@ version = "0.13"
|
|||
|
||||
[dependencies.chrono]
|
||||
version = "0.4"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.iana-time-zone]
|
||||
version = "0.1"
|
||||
default-features = false
|
||||
features = ["alloc", "serde"]
|
||||
|
||||
[dependencies.csv]
|
||||
version = "1.1"
|
||||
|
@ -39,14 +37,24 @@ features = ["cargo"]
|
|||
[dependencies.directories]
|
||||
version = "4.0"
|
||||
|
||||
[dependencies.env_logger]
|
||||
version = "0.9"
|
||||
|
||||
[dependencies.futures]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.ics]
|
||||
version = "0.5"
|
||||
[dependencies.icalendar]
|
||||
version = "0.13.0"
|
||||
features = ["parser"]
|
||||
|
||||
[dependencies.minicaldav]
|
||||
version = "0.2"
|
||||
[dependencies.libxml]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1.6"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11"
|
||||
|
@ -72,8 +80,5 @@ version = "0.5"
|
|||
version = "1"
|
||||
features = ["rt-multi-thread", "net", "macros"]
|
||||
|
||||
[dependencies.ureq]
|
||||
version = "2.5"
|
||||
|
||||
[dependencies.webbrowser]
|
||||
version = "0.7"
|
||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,7 +1,7 @@
|
|||
# SPDX-FileCopyrightText: 2021 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
FROM docker.io/rust:latest@sha256:490d4448c29f5407ee6eaf62f081a82b2741b4416c8e20aef7c01b68776802c2
|
||||
FROM docker.io/rust:latest@sha256:4f1d43c216d995c2f734d7c682bc3e2abe3e110961cda4ae0743ce3944e673a2
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
|
@ -9,11 +9,17 @@ RUN apt update && \
|
|||
apt install -y \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
python3-pip \
|
||||
&& \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN cargo install -f -- \
|
||||
RUN pip3 install reuse
|
||||
|
||||
RUN rustup component add rustfmt
|
||||
|
||||
RUN cargo install --locked -f -- \
|
||||
cargo-tarpaulin \
|
||||
cargo-deny \
|
||||
cargo2junit \
|
||||
&& \
|
||||
rm -rf "${HOME}/.cargo/registry" "${HOME}/.cargo/git"
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
# SPDX-FileCopyrightText: 2021 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# This template contains all of the possible sections and their default values
|
||||
|
||||
# Note that all fields that take a lint level have these possible values:
|
||||
# * deny - An error will be produced and the check will fail
|
||||
# * warn - A warning will be produced, but the check will not fail
|
||||
# * allow - No warning or error will be produced, though in some cases a note
|
||||
# will be
|
||||
|
||||
# The values provided in this template are the default values that will be used
|
||||
# when any section or field is not specified in your own configuration
|
||||
|
||||
# If 1 or more target triples (and optionally, target_features) are specified,
|
||||
# only the specified targets will be checked when running `cargo deny check`.
|
||||
# This means, if a particular package is only ever used as a target specific
|
||||
# dependency, such as, for example, the `nix` crate only being used via the
|
||||
# `target_family = "unix"` configuration, that only having windows targets in
|
||||
# this list would mean the nix crate, as well as any of its exclusive
|
||||
# dependencies not shared by any other crates, would be ignored, as the target
|
||||
# list here is effectively saying which targets you are building for.
|
||||
targets = [
|
||||
# The triple can be any string, but only the target triples built in to
|
||||
# rustc (as of 1.40) can be checked against actual config expressions
|
||||
#{ triple = "x86_64-unknown-linux-musl" },
|
||||
# You can also specify which target_features you promise are enabled for a
|
||||
# particular target. target_features are currently not validated against
|
||||
# the actual valid features supported by the target architecture.
|
||||
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
|
||||
]
|
||||
|
||||
# This section is considered when running `cargo deny check advisories`
|
||||
# More documentation for the advisories section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
||||
[advisories]
|
||||
# The path where the advisory database is cloned/fetched into
|
||||
db-path = "~/.cargo/advisory-db"
|
||||
# The url(s) of the advisory databases to use
|
||||
db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||
# The lint level for security vulnerabilities
|
||||
vulnerability = "deny"
|
||||
# The lint level for unmaintained crates
|
||||
unmaintained = "warn"
|
||||
# The lint level for crates that have been yanked from their source registry
|
||||
yanked = "warn"
|
||||
# The lint level for crates with security notices.
|
||||
notice = "warn"
|
||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||
# output a note when they are encountered.
|
||||
ignore = [
|
||||
#"RUSTSEC-0000-0000",
|
||||
"RUSTSEC-2020-0071",
|
||||
]
|
||||
# Threshold for security vulnerabilities, any vulnerability with a CVSS score
|
||||
# lower than the range specified will be ignored. Note that ignored advisories
|
||||
# will still output a note when they are encountered.
|
||||
# * None - CVSS Score 0.0
|
||||
# * Low - CVSS Score 0.1 - 3.9
|
||||
# * Medium - CVSS Score 4.0 - 6.9
|
||||
# * High - CVSS Score 7.0 - 8.9
|
||||
# * Critical - CVSS Score 9.0 - 10.0
|
||||
#severity-threshold =
|
||||
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
|
||||
# See Git Authentication for more information about setting up git authentication.
|
||||
#git-fetch-with-cli = true
|
||||
|
||||
# This section is considered when running `cargo deny check licenses`
|
||||
# More documentation for the licenses section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
||||
[licenses]
|
||||
# The lint level for crates which do not have a detectable license
|
||||
unlicensed = "deny"
|
||||
# List of explicitly allowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
allow = [
|
||||
#"MIT",
|
||||
#"Apache-2.0",
|
||||
#"Apache-2.0 WITH LLVM-exception",
|
||||
]
|
||||
# List of explicitly disallowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
deny = [
|
||||
#"Nokia",
|
||||
]
|
||||
# Lint level for licenses considered copyleft
|
||||
copyleft = "allow"
|
||||
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
|
||||
# * both - The license will be approved if it is both OSI-approved *AND* FSF
|
||||
# * either - The license will be approved if it is either OSI-approved *OR* FSF
|
||||
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
|
||||
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
|
||||
# * neither - This predicate is ignored and the default lint level is used
|
||||
allow-osi-fsf-free = "both"
|
||||
# Lint level used when no other predicates are matched
|
||||
# 1. License isn't in the allow or deny lists
|
||||
# 2. License isn't copyleft
|
||||
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
|
||||
default = "deny"
|
||||
# The confidence threshold for detecting a license from license text.
|
||||
# The higher the value, the more closely the license text must be to the
|
||||
# canonical license text of a valid SPDX license file.
|
||||
# [possible values: any between 0.0 and 1.0].
|
||||
confidence-threshold = 0.8
|
||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||
# aren't accepted for every possible crate as with the normal allow list
|
||||
exceptions = [
|
||||
# Each entry is the crate and version constraint, and its specific allow
|
||||
# list
|
||||
#{ allow = ["Zlib"], name = "adler32", version = "*" },
|
||||
{ allow = ["Unicode-DFS-2016"], name = "unicode-ident", version = "*" },
|
||||
]
|
||||
|
||||
# Some crates don't have (easily) machine readable licensing information,
|
||||
# adding a clarification entry for it allows you to manually specify the
|
||||
# licensing information
|
||||
#[[licenses.clarify]]
|
||||
# The name of the crate the clarification applies to
|
||||
#name = "ring"
|
||||
# The optional version constraint for the crate
|
||||
#version = "*"
|
||||
# The SPDX expression for the license requirements of the crate
|
||||
#expression = "MIT AND ISC AND OpenSSL"
|
||||
# One or more files in the crate's source used as the "source of truth" for
|
||||
# the license expression. If the contents match, the clarification will be used
|
||||
# when running the license check, otherwise the clarification will be ignored
|
||||
# and the crate will be checked normally, which may produce warnings or errors
|
||||
# depending on the rest of your configuration
|
||||
#license-files = [
|
||||
# Each entry is a crate relative path, and the (opaque) hash of its contents
|
||||
#{ path = "LICENSE", hash = 0xbd0eed23 }
|
||||
#]
|
||||
|
||||
[licenses.private]
|
||||
# If true, ignores workspace crates that aren't published, or are only
|
||||
# published to private registries.
|
||||
# To see how to mark a crate as unpublished (to the official registry),
|
||||
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
|
||||
ignore = false
|
||||
# One or more private registries that you might publish crates to, if a crate
|
||||
# is only published to private registries, and ignore is true, the crate will
|
||||
# not have its license(s) checked
|
||||
registries = [
|
||||
#"https://sekretz.com/registry
|
||||
]
|
||||
|
||||
# This section is considered when running `cargo deny check bans`.
|
||||
# More documentation about the 'bans' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
||||
[bans]
|
||||
# Lint level for when multiple versions of the same crate are detected
|
||||
multiple-versions = "warn"
|
||||
# Lint level for when a crate version requirement is `*`
|
||||
wildcards = "allow"
|
||||
# The graph highlighting used when creating dotgraphs for crates
|
||||
# with multiple versions
|
||||
# * lowest-version - The path to the lowest versioned duplicate is highlighted
|
||||
# * simplest-path - The path to the version with the fewest edges is highlighted
|
||||
# * all - Both lowest-version and simplest-path are used
|
||||
highlight = "all"
|
||||
# List of crates that are allowed. Use with care!
|
||||
allow = [
|
||||
#{ name = "ansi_term", version = "=0.11.0" },
|
||||
]
|
||||
# List of crates to deny
|
||||
deny = [
|
||||
# Each entry the name of a crate and a version range. If version is
|
||||
# not specified, all versions will be matched.
|
||||
#{ name = "ansi_term", version = "=0.11.0" },
|
||||
#
|
||||
# Wrapper crates can optionally be specified to allow the crate when it
|
||||
# is a direct dependency of the otherwise banned crate
|
||||
#{ name = "ansi_term", version = "=0.11.0", wrappers = [] },
|
||||
]
|
||||
# Certain crates/versions that will be skipped when doing duplicate detection.
|
||||
skip = [
|
||||
#{ name = "ansi_term", version = "=0.11.0" },
|
||||
]
|
||||
# Similarly to `skip` allows you to skip certain crates during duplicate
|
||||
# detection. Unlike skip, it also includes the entire tree of transitive
|
||||
# dependencies starting at the specified crate, up to a certain depth, which is
|
||||
# by default infinite
|
||||
skip-tree = [
|
||||
#{ name = "ansi_term", version = "=0.11.0", depth = 20 },
|
||||
]
|
||||
|
||||
# This section is considered when running `cargo deny check sources`.
|
||||
# More documentation about the 'sources' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
||||
[sources]
|
||||
# Lint level for what to happen when a crate from a crate registry that is not
|
||||
# in the allow list is encountered
|
||||
unknown-registry = "warn"
|
||||
# Lint level for what to happen when a crate from a git repository that is not
|
||||
# in the allow list is encountered
|
||||
unknown-git = "warn"
|
||||
# List of URLs for allowed crate registries. Defaults to the crates.io index
|
||||
# if not specified. If it is specified but empty, no registries are allowed.
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
# List of URLs for allowed Git repositories
|
||||
allow-git = []
|
||||
|
||||
[sources.allow-org]
|
||||
# 1 or more github.com organizations to allow git sources for
|
||||
#github = [""]
|
||||
# 1 or more gitlab.com organizations to allow git sources for
|
||||
#gitlab = [""]
|
||||
# 1 or more bitbucket.org organizations to allow git sources for
|
||||
#bitbucket = [""]
|
|
@ -1,366 +1,366 @@
|
|||
"day","wday","lunch","dinner"
|
||||
2022-01-01,"sabato",,
|
||||
2022-01-02,"domenica",,
|
||||
2022-01-03,"lunedì",,
|
||||
2022-01-04,"martedì",,
|
||||
2022-01-05,"mercoledì",,
|
||||
2022-01-06,"giovedì",,
|
||||
2022-01-07,"venerdì",,
|
||||
2022-01-08,"sabato",,
|
||||
2022-01-09,"domenica",,
|
||||
2022-01-10,"lunedì",,
|
||||
2022-01-11,"martedì",,
|
||||
2022-01-12,"mercoledì",,
|
||||
2022-01-13,"giovedì",,
|
||||
2022-01-14,"venerdì",,
|
||||
2022-01-15,"sabato",,
|
||||
2022-01-16,"domenica",,
|
||||
2022-01-17,"lunedì",,
|
||||
2022-01-18,"martedì",,
|
||||
2022-01-19,"mercoledì",,
|
||||
2022-01-20,"giovedì",,
|
||||
2022-01-21,"venerdì",,
|
||||
2022-01-22,"sabato",,
|
||||
2022-01-23,"domenica",,
|
||||
2022-01-24,"lunedì",,
|
||||
2022-01-25,"martedì",,
|
||||
2022-01-26,"mercoledì",,
|
||||
2022-01-27,"giovedì",,
|
||||
2022-01-28,"venerdì",,
|
||||
2022-01-29,"sabato",,
|
||||
2022-01-30,"domenica",,
|
||||
2022-01-31,"lunedì",,
|
||||
2022-02-01,"martedì",,
|
||||
2022-02-02,"mercoledì",,
|
||||
2022-02-03,"giovedì",,
|
||||
2022-02-04,"venerdì",,
|
||||
2022-02-05,"sabato",,
|
||||
2022-02-06,"domenica",,
|
||||
2022-02-07,"lunedì",,
|
||||
2022-02-08,"martedì",,
|
||||
2022-02-09,"mercoledì",,
|
||||
2022-02-10,"giovedì",,
|
||||
2022-02-11,"venerdì",,
|
||||
2022-02-12,"sabato",,
|
||||
2022-02-13,"domenica",,
|
||||
2022-02-14,"lunedì",,
|
||||
2022-02-15,"martedì",,
|
||||
2022-02-16,"mercoledì",,
|
||||
2022-02-17,"giovedì",,
|
||||
2022-02-18,"venerdì",,
|
||||
2022-02-19,"sabato",,
|
||||
2022-02-20,"domenica",,
|
||||
2022-02-21,"lunedì",,
|
||||
2022-02-22,"martedì",,
|
||||
2022-02-23,"mercoledì",,
|
||||
2022-02-24,"giovedì",,
|
||||
2022-02-25,"venerdì",,
|
||||
2022-02-26,"sabato",,
|
||||
2022-02-27,"domenica",,
|
||||
2022-02-28,"lunedì",,
|
||||
2022-03-01,"martedì",,
|
||||
2022-03-02,"mercoledì",,
|
||||
2022-03-03,"giovedì",,
|
||||
2022-03-04,"venerdì",,
|
||||
2022-03-05,"sabato",,
|
||||
2022-03-06,"domenica",,
|
||||
2022-03-07,"lunedì",,
|
||||
2022-03-08,"martedì",,
|
||||
2022-03-09,"mercoledì",,
|
||||
2022-03-10,"giovedì",,
|
||||
2022-03-11,"venerdì",,
|
||||
2022-03-12,"sabato",,
|
||||
2022-03-13,"domenica",,
|
||||
2022-03-14,"lunedì",,
|
||||
2022-03-15,"martedì",,
|
||||
2022-03-16,"mercoledì",,
|
||||
2022-03-17,"giovedì",,
|
||||
2022-03-18,"venerdì",,
|
||||
2022-03-19,"sabato",,
|
||||
2022-03-20,"domenica",,
|
||||
2022-03-21,"lunedì",,
|
||||
2022-03-22,"martedì",,
|
||||
2022-03-23,"mercoledì",,
|
||||
2022-03-24,"giovedì",,
|
||||
2022-03-25,"venerdì",,
|
||||
2022-03-26,"sabato",,
|
||||
2022-03-27,"domenica",,
|
||||
2022-03-28,"lunedì",,
|
||||
2022-03-29,"martedì",,
|
||||
2022-03-30,"mercoledì",,
|
||||
2022-03-31,"giovedì",,
|
||||
2022-04-01,"venerdì",,
|
||||
2022-04-02,"sabato",,
|
||||
2022-04-03,"domenica",,
|
||||
2022-04-04,"lunedì",,
|
||||
2022-04-05,"martedì",,
|
||||
2022-04-06,"mercoledì",,
|
||||
2022-04-07,"giovedì",,
|
||||
2022-04-08,"venerdì",,
|
||||
2022-04-09,"sabato",,
|
||||
2022-04-10,"domenica",,
|
||||
2022-04-11,"lunedì",,
|
||||
2022-04-12,"martedì",,
|
||||
2022-04-13,"mercoledì",,
|
||||
2022-04-14,"giovedì",,
|
||||
2022-04-15,"venerdì",,
|
||||
2022-04-16,"sabato",,
|
||||
2022-04-17,"domenica",,
|
||||
2022-04-18,"lunedì",,
|
||||
2022-04-19,"martedì",,
|
||||
2022-04-20,"mercoledì",,
|
||||
2022-04-21,"giovedì",,
|
||||
2022-04-22,"venerdì",,
|
||||
2022-04-23,"sabato",,
|
||||
2022-04-24,"domenica",,
|
||||
2022-04-25,"lunedì",,
|
||||
2022-04-26,"martedì",,
|
||||
2022-04-27,"mercoledì",,
|
||||
2022-04-28,"giovedì",,
|
||||
2022-04-29,"venerdì",,
|
||||
2022-04-30,"sabato",,
|
||||
2022-05-01,"domenica",,
|
||||
2022-05-02,"lunedì",,
|
||||
2022-05-03,"martedì",,
|
||||
2022-05-04,"mercoledì",,
|
||||
2022-05-05,"giovedì",,
|
||||
2022-05-06,"venerdì",,
|
||||
2022-05-07,"sabato",,
|
||||
2022-05-08,"domenica",,
|
||||
2022-05-09,"lunedì",,
|
||||
2022-05-10,"martedì",,
|
||||
2022-05-11,"mercoledì",,
|
||||
2022-05-12,"giovedì",,
|
||||
2022-05-13,"venerdì",,
|
||||
2022-05-14,"sabato",,
|
||||
2022-05-15,"domenica",,
|
||||
2022-05-16,"lunedì",,
|
||||
2022-05-17,"martedì",,
|
||||
2022-05-18,"mercoledì",,
|
||||
2022-05-19,"giovedì",,
|
||||
2022-05-20,"venerdì",,
|
||||
2022-05-21,"sabato",,
|
||||
2022-05-22,"domenica",,
|
||||
2022-05-23,"lunedì",,
|
||||
2022-05-24,"martedì",,
|
||||
2022-05-25,"mercoledì",,
|
||||
2022-05-26,"giovedì",,
|
||||
2022-05-27,"venerdì",,
|
||||
2022-05-28,"sabato",,
|
||||
2022-05-29,"domenica",,
|
||||
2022-05-30,"lunedì",,
|
||||
2022-05-31,"martedì",,
|
||||
2022-06-01,"mercoledì",,
|
||||
2022-06-02,"giovedì",,
|
||||
2022-06-03,"venerdì",,
|
||||
2022-06-04,"sabato",,
|
||||
2022-06-05,"domenica",,
|
||||
2022-06-06,"lunedì",,
|
||||
2022-06-07,"martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
2022-06-08,"mercoledì",,
|
||||
2022-06-09,"giovedì",,
|
||||
2022-06-10,"venerdì",,
|
||||
2022-06-11,"sabato",,
|
||||
2022-06-12,"domenica",,
|
||||
2022-06-13,"lunedì",,
|
||||
2022-06-14,"martedì",,
|
||||
2022-06-15,"mercoledì",,
|
||||
2022-06-16,"giovedì",,
|
||||
2022-06-17,"venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||
2022-06-18,"sabato",,
|
||||
2022-06-19,"domenica",,
|
||||
2022-06-20,"lunedì",,
|
||||
2022-06-21,"martedì",,
|
||||
2022-06-22,"mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
2022-06-23,"giovedì",,
|
||||
2022-06-24,"venerdì",,
|
||||
2022-06-25,"sabato",,
|
||||
2022-06-26,"domenica",,
|
||||
2022-06-27,"lunedì",,
|
||||
2022-06-28,"martedì",,
|
||||
2022-06-29,"mercoledì",,
|
||||
2022-06-30,"giovedì",,
|
||||
2022-07-01,"venerdì",,
|
||||
2022-07-02,"sabato",,
|
||||
2022-07-03,"domenica",,
|
||||
2022-07-04,"lunedì",,
|
||||
2022-07-05,"martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
2022-07-06,"mercoledì",,
|
||||
2022-07-07,"giovedì",,
|
||||
2022-07-08,"venerdì",,
|
||||
2022-07-09,"sabato",,
|
||||
2022-07-10,"domenica",,
|
||||
2022-07-11,"lunedì",,
|
||||
2022-07-12,"martedì",,
|
||||
2022-07-13,"mercoledì",,
|
||||
2022-07-14,"giovedì",,
|
||||
2022-07-15,"venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||
2022-07-16,"sabato",,
|
||||
2022-07-17,"domenica",,
|
||||
2022-07-18,"lunedì",,
|
||||
2022-07-19,"martedì",,
|
||||
2022-07-20,"mercoledì",,
|
||||
2022-07-21,"giovedì",,
|
||||
2022-07-22,"venerdì",,
|
||||
2022-07-23,"sabato",,
|
||||
2022-07-24,"domenica",,
|
||||
2022-07-25,"lunedì",,
|
||||
2022-07-26,"martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
2022-07-27,"mercoledì",,
|
||||
2022-07-28,"giovedì",,
|
||||
2022-07-29,"venerdì",,
|
||||
2022-07-30,"sabato",,
|
||||
2022-07-31,"domenica",,
|
||||
"2022-01-01","sabato",,
|
||||
"2022-01-02","domenica",,
|
||||
"2022-01-03","lunedì",,
|
||||
"2022-01-04","martedì",,
|
||||
"2022-01-05","mercoledì",,
|
||||
"2022-01-06","giovedì",,
|
||||
"2022-01-07","venerdì",,
|
||||
"2022-01-08","sabato",,
|
||||
"2022-01-09","domenica","https://ricette.giallozafferano.it/Pollo-alla-cacciatora.html","https://ricette.giallozafferano.it/Vellutata-di-porri-con-crostini-saporiti.html"
|
||||
"2022-01-10","lunedì",,
|
||||
"2022-01-11","martedì",,
|
||||
"2022-01-12","mercoledì",,
|
||||
"2022-01-13","giovedì",,
|
||||
"2022-01-14","venerdì",,"https://ricette.giallozafferano.it/Polpette-al-sugo.html"
|
||||
"2022-01-15","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html","https://ricette.giallozafferano.it/Risotto-radicchio-e-pancetta.html"
|
||||
"2022-01-16","domenica",,
|
||||
"2022-01-17","lunedì",,"https://ricette.giallozafferano.it/Spatzle-di-spinaci.html"
|
||||
"2022-01-18","martedì",,
|
||||
"2022-01-19","mercoledì",,
|
||||
"2022-01-20","giovedì",,
|
||||
"2022-01-21","venerdì",,
|
||||
"2022-01-22","sabato","https://ricette.giallozafferano.it/Gnocchi-alla-sorrentina.html",
|
||||
"2022-01-23","domenica",,
|
||||
"2022-01-24","lunedì",,
|
||||
"2022-01-25","martedì",,
|
||||
"2022-01-26","mercoledì",,
|
||||
"2022-01-27","giovedì",,
|
||||
"2022-01-28","venerdì",,
|
||||
"2022-01-29","sabato",,"https://ricette.giallozafferano.it/Costine-al-forno.html"
|
||||
"2022-01-30","domenica",,
|
||||
"2022-01-31","lunedì",,
|
||||
"2022-02-01","martedì",,
|
||||
"2022-02-02","mercoledì",,
|
||||
"2022-02-03","giovedì",,
|
||||
"2022-02-04","venerdì",,
|
||||
"2022-02-05","sabato",,"https://ricette.giallozafferano.it/Chili-con-carne.html"
|
||||
"2022-02-06","domenica",,
|
||||
"2022-02-07","lunedì",,
|
||||
"2022-02-08","martedì",,
|
||||
"2022-02-09","mercoledì",,"https://ricette.giallozafferano.it/Vellutata-di-porri-con-crostini-saporiti.html"
|
||||
"2022-02-10","giovedì",,
|
||||
"2022-02-11","venerdì",,
|
||||
"2022-02-12","sabato",,
|
||||
"2022-02-13","domenica",,"https://ricette.giallozafferano.it/Spatzle-di-spinaci.html"
|
||||
"2022-02-14","lunedì",,
|
||||
"2022-02-15","martedì",,
|
||||
"2022-02-16","mercoledì",,"https://ricette.giallozafferano.it/Risotto-radicchio-e-pancetta.html"
|
||||
"2022-02-17","giovedì",,
|
||||
"2022-02-18","venerdì",,
|
||||
"2022-02-19","sabato",,"https://ricette.giallozafferano.it/Polpette-al-sugo.html"
|
||||
"2022-02-20","domenica",,
|
||||
"2022-02-21","lunedì",,
|
||||
"2022-02-22","martedì",,
|
||||
"2022-02-23","mercoledì",,
|
||||
"2022-02-24","giovedì",,"https://ricette.giallozafferano.it/Orata-al-forno.html"
|
||||
"2022-02-25","venerdì",,"https://ricette.giallozafferano.it/Torta-rustica.html"
|
||||
"2022-02-26","sabato","https://ricette.giallozafferano.it/Gnudi.html",
|
||||
"2022-02-27","domenica",,
|
||||
"2022-02-28","lunedì",,
|
||||
"2022-03-01","martedì",,
|
||||
"2022-03-02","mercoledì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
||||
"2022-03-03","giovedì",,
|
||||
"2022-03-04","venerdì",,
|
||||
"2022-03-05","sabato",,
|
||||
"2022-03-06","domenica","https://ricette.giallozafferano.it/Torta-Pasqualina.html",
|
||||
"2022-03-07","lunedì",,
|
||||
"2022-03-08","martedì",,"https://ricette.giallozafferano.it/Strozzapreti-cacio-cozze-e-pepe.html"
|
||||
"2022-03-09","mercoledì",,"https://ricette.giallozafferano.it/Saltimbocca-alla-Romana.html"
|
||||
"2022-03-10","giovedì",,
|
||||
"2022-03-11","venerdì",,
|
||||
"2022-03-12","sabato",,"https://ricette.giallozafferano.it/Costine-al-forno.html"
|
||||
"2022-03-13","domenica",,
|
||||
"2022-03-14","lunedì",,
|
||||
"2022-03-15","martedì",,
|
||||
"2022-03-16","mercoledì",,
|
||||
"2022-03-17","giovedì",,"https://ricette.giallozafferano.it/Filetti-di-salmone-su-julienne-di-cavoletti-di-bruxelles-porri-e-carote.html"
|
||||
"2022-03-18","venerdì",,"https://ricette.giallozafferano.it/Torta-rustica.html"
|
||||
"2022-03-19","sabato",,
|
||||
"2022-03-20","domenica",,
|
||||
"2022-03-21","lunedì",,
|
||||
"2022-03-22","martedì",,
|
||||
"2022-03-23","mercoledì",,
|
||||
"2022-03-24","giovedì",,
|
||||
"2022-03-25","venerdì",,
|
||||
"2022-03-26","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-03-27","domenica",,
|
||||
"2022-03-28","lunedì",,
|
||||
"2022-03-29","martedì",,
|
||||
"2022-03-30","mercoledì",,
|
||||
"2022-03-31","giovedì",,
|
||||
"2022-04-01","venerdì",,
|
||||
"2022-04-02","sabato",,
|
||||
"2022-04-03","domenica",,
|
||||
"2022-04-04","lunedì",,
|
||||
"2022-04-05","martedì",,
|
||||
"2022-04-06","mercoledì",,
|
||||
"2022-04-07","giovedì",,
|
||||
"2022-04-08","venerdì",,
|
||||
"2022-04-09","sabato",,
|
||||
"2022-04-10","domenica",,
|
||||
"2022-04-11","lunedì",,
|
||||
"2022-04-12","martedì",,
|
||||
"2022-04-13","mercoledì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
||||
"2022-04-14","giovedì",,
|
||||
"2022-04-15","venerdì",,
|
||||
"2022-04-16","sabato",,"https://ricette.giallozafferano.it/Couscous-alla-marocchina.html"
|
||||
"2022-04-17","domenica",,
|
||||
"2022-04-18","lunedì",,
|
||||
"2022-04-19","martedì",,
|
||||
"2022-04-20","mercoledì",,
|
||||
"2022-04-21","giovedì",,
|
||||
"2022-04-22","venerdì",,"https://ricette.giallozafferano.it/Risotto-agli-asparagi-e-scampi.html"
|
||||
"2022-04-23","sabato",,
|
||||
"2022-04-24","domenica","https://ricette.giallozafferano.it/Torta-Pasqualina.html",
|
||||
"2022-04-25","lunedì",,
|
||||
"2022-04-26","martedì",,
|
||||
"2022-04-27","mercoledì",,"https://ricette.giallozafferano.it/Orata-al-forno.html"
|
||||
"2022-04-28","giovedì",,
|
||||
"2022-04-29","venerdì",,"https://ricette.giallozafferano.it/Cordon-bleu-di-melanzane.html"
|
||||
"2022-04-30","sabato",,
|
||||
"2022-05-01","domenica",,
|
||||
"2022-05-02","lunedì",,
|
||||
"2022-05-03","martedì",,
|
||||
"2022-05-04","mercoledì",,
|
||||
"2022-05-05","giovedì",,
|
||||
"2022-05-06","venerdì",,
|
||||
"2022-05-07","sabato",,
|
||||
"2022-05-08","domenica",,
|
||||
"2022-05-09","lunedì",,
|
||||
"2022-05-10","martedì",,
|
||||
"2022-05-11","mercoledì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
||||
"2022-05-12","giovedì",,
|
||||
"2022-05-13","venerdì",,
|
||||
"2022-05-14","sabato",,
|
||||
"2022-05-15","domenica",,
|
||||
"2022-05-16","lunedì",,
|
||||
"2022-05-17","martedì",,
|
||||
"2022-05-18","mercoledì",,"https://ricette.giallozafferano.it/Risotto-agli-asparagi-e-scampi.html"
|
||||
"2022-05-19","giovedì",,
|
||||
"2022-05-20","venerdì",,
|
||||
"2022-05-21","sabato",,"https://ricette.giallozafferano.it/Couscous-alla-marocchina.html"
|
||||
"2022-05-22","domenica","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-05-23","lunedì",,
|
||||
"2022-05-24","martedì",,
|
||||
"2022-05-25","mercoledì",,
|
||||
"2022-05-26","giovedì",,"https://ricette.giallozafferano.it/Saltimbocca-alla-Romana.html"
|
||||
"2022-05-27","venerdì",,
|
||||
"2022-05-28","sabato",,
|
||||
"2022-05-29","domenica","https://ricette.giallozafferano.it/Polpo-alla-Luciana.html",
|
||||
"2022-05-30","lunedì",,
|
||||
"2022-05-31","martedì",,
|
||||
"2022-06-01","mercoledì",,"https://ricette.giallozafferano.it/Riso-alla-cantonese.html"
|
||||
"2022-06-02","giovedì",,
|
||||
"2022-06-03","venerdì",,
|
||||
"2022-06-04","sabato",,
|
||||
"2022-06-05","domenica",,
|
||||
"2022-06-06","lunedì",,
|
||||
"2022-06-07","martedì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-06-08","mercoledì",,
|
||||
"2022-06-09","giovedì",,
|
||||
"2022-06-10","venerdì",,"https://ricette.giallozafferano.it/Verdure-gratinate-al-forno.html"
|
||||
"2022-06-11","sabato",,
|
||||
"2022-06-12","domenica",,"https://ricette.giallozafferano.it/Riso-alla-cantonese.html"
|
||||
"2022-06-13","lunedì",,"https://ricette.giallozafferano.it/Petto-di-pollo-ai-peperoni.html"
|
||||
"2022-06-14","martedì",,"https://ricette.giallozafferano.it/Insalata-di-pasta-Mediterranea.html"
|
||||
"2022-06-15","mercoledì",,"https://ricette.giallozafferano.it/Cocotte-di-quinoa.html"
|
||||
"2022-06-16","giovedì",,
|
||||
"2022-06-17","venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||
"2022-06-18","sabato","https://ricette.giallozafferano.it/Insalata-di-ceci-estiva.html",
|
||||
"2022-06-19","domenica",,
|
||||
"2022-06-20","lunedì",,
|
||||
"2022-06-21","martedì",,
|
||||
"2022-06-22","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-06-23","giovedì",,
|
||||
"2022-06-24","venerdì",,
|
||||
"2022-06-25","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-06-26","domenica",,
|
||||
"2022-06-27","lunedì",,
|
||||
"2022-06-28","martedì",,
|
||||
"2022-06-29","mercoledì",,
|
||||
"2022-06-30","giovedì",,
|
||||
"2022-07-01","venerdì",,
|
||||
"2022-07-02","sabato",,
|
||||
"2022-07-03","domenica",,
|
||||
"2022-07-04","lunedì",,
|
||||
"2022-07-05","martedì",,"https://ricette.giallozafferano.it/Insalata-di-ceci-estiva.html"
|
||||
"2022-07-06","mercoledì",,"https://ricette.giallozafferano.it/Pasta-con-le-melanzane.html"
|
||||
"2022-07-07","giovedì",,
|
||||
"2022-07-08","venerdì",,
|
||||
"2022-07-09","sabato",,
|
||||
"2022-07-10","domenica",,
|
||||
"2022-07-11","lunedì",,
|
||||
"2022-07-12","martedì",,
|
||||
"2022-07-13","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-07-14","giovedì",,
|
||||
"2022-07-15","venerdì",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||
"2022-07-16","sabato",,
|
||||
"2022-07-17","domenica",,
|
||||
"2022-07-18","lunedì",,
|
||||
"2022-07-19","martedì",,"https://ricette.giallozafferano.it/Verdure-gratinate-al-forno.html"
|
||||
"2022-07-20","mercoledì",,
|
||||
"2022-07-21","giovedì",,"https://ricette.giallozafferano.it/Insalata-di-pasta-Mediterranea.html"
|
||||
"2022-07-22","venerdì",,
|
||||
"2022-07-23","sabato",,"https://ricette.giallozafferano.it/Cocotte-di-quinoa.html"
|
||||
"2022-07-24","domenica",,
|
||||
"2022-07-25","lunedì",,
|
||||
"2022-07-26","martedì",,
|
||||
"2022-07-27","mercoledì",,
|
||||
"2022-07-28","giovedì",,
|
||||
"2022-07-29","venerdì",,"https://ricette.giallozafferano.it/Orata-al-forno.html"
|
||||
"2022-07-30","sabato",,
|
||||
"2022-07-31","domenica",,
|
||||
"2022-08-01","lunedì",,"https://ricette.giallozafferano.it/Riso-freddo-con-tonno-zucchine-e-limone.html"
|
||||
"2022-08-02","martedì",,
|
||||
"2022-08-03","mercoledì",,
|
||||
"2022-08-04","giovedì",,
|
||||
"2022-08-03","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-08-04","giovedì",,"https://ricette.giallozafferano.it/Petto-di-pollo-ai-peperoni.html"
|
||||
"2022-08-05","venerdì",,
|
||||
"2022-08-06","sabato",,
|
||||
"2022-08-07","domenica",,
|
||||
"2022-08-08","lunedì",,
|
||||
"2022-08-09","martedì",,
|
||||
"2022-08-09","martedì",,"https://ricette.giallozafferano.it/Insalata-di-pasta-Mediterranea.html"
|
||||
"2022-08-10","mercoledì",,
|
||||
"2022-08-11","giovedì",,
|
||||
"2022-08-11","giovedì",,"https://ricette.giallozafferano.it/Verdure-gratinate-al-forno.html"
|
||||
"2022-08-12","venerdì",,
|
||||
"2022-08-13","sabato",,
|
||||
"2022-08-14","domenica",,
|
||||
"2022-08-15","lunedì",,
|
||||
"2022-08-15","lunedì",,"https://ricette.giallozafferano.it/Pasta-con-le-melanzane.html"
|
||||
"2022-08-16","martedì",,
|
||||
"2022-08-17","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-08-17","mercoledì",,"https://ricette.giallozafferano.it/Cocotte-di-quinoa.html"
|
||||
"2022-08-18","giovedì",,
|
||||
"2022-08-19","venerdì",,
|
||||
"2022-08-20","sabato",,"https://ricette.giallozafferano.it/Salmorejo.html"
|
||||
"2022-08-21","domenica",,
|
||||
"2022-08-22","lunedì",,
|
||||
"2022-08-23","martedì",,
|
||||
"2022-08-24","mercoledì",,
|
||||
"2022-08-24","mercoledì",,"https://ricette.giallozafferano.it/Pasta-fredda-con-pesto-senz-aglio.html"
|
||||
"2022-08-25","giovedì",,
|
||||
"2022-08-26","venerdì",,
|
||||
"2022-08-27","sabato",,
|
||||
"2022-08-27","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-08-28","domenica",,
|
||||
"2022-08-29","lunedì",,
|
||||
"2022-08-30","martedì",,
|
||||
"2022-08-31","mercoledì",,
|
||||
"2022-09-01","giovedì",,
|
||||
"2022-09-02","venerdì",,
|
||||
"2022-09-02","venerdì",,"https://ricette.giallozafferano.it/Petto-di-pollo-ai-peperoni.html"
|
||||
"2022-09-03","sabato",,
|
||||
"2022-09-04","domenica",,
|
||||
"2022-09-05","lunedì",,
|
||||
"2022-09-06","martedì",,
|
||||
"2022-09-07","mercoledì",,
|
||||
"2022-09-08","giovedì",,
|
||||
"2022-09-08","giovedì",,"https://ricette.giallozafferano.it/Pasta-con-le-melanzane.html"
|
||||
"2022-09-09","venerdì",,
|
||||
"2022-09-10","sabato",,
|
||||
"2022-09-11","domenica",,
|
||||
"2022-09-12","lunedì",,
|
||||
"2022-09-11","domenica","https://ricette.giallozafferano.it/Polpo-alla-Luciana.html",
|
||||
"2022-09-12","lunedì",,"https://ricette.giallozafferano.it/Pennette-con-speck-e-zucchine.html"
|
||||
"2022-09-13","martedì",,
|
||||
"2022-09-14","mercoledì",,
|
||||
"2022-09-14","mercoledì",,"https://ricette.giallozafferano.it/Scaloppine-ai-funghi.html"
|
||||
"2022-09-15","giovedì",,
|
||||
"2022-09-16","venerdì",,
|
||||
"2022-09-16","venerdì",,"https://ricette.giallozafferano.it/Cordon-bleu-di-melanzane.html"
|
||||
"2022-09-17","sabato",,
|
||||
"2022-09-18","domenica",,
|
||||
"2022-09-19","lunedì",,
|
||||
"2022-09-20","martedì",,
|
||||
"2022-09-21","mercoledì",,
|
||||
"2022-09-22","giovedì",,
|
||||
"2022-09-21","mercoledì",,"https://ricette.giallozafferano.it/Strozzapreti-cacio-cozze-e-pepe.html"
|
||||
"2022-09-22","giovedì",,"https://ricette.giallozafferano.it/Vellutata-di-porri-con-crostini-saporiti.html"
|
||||
"2022-09-23","venerdì",,
|
||||
"2022-09-24","sabato",,
|
||||
"2022-09-25","domenica",,
|
||||
"2022-09-26","lunedì",,
|
||||
"2022-09-24","sabato","https://ricette.giallozafferano.it/Gnudi.html",
|
||||
"2022-09-25","domenica","https://ricette.giallozafferano.it/Pollo-alla-cacciatora.html",
|
||||
"2022-09-26","lunedì",,"https://ricette.giallozafferano.it/Mezze-maniche-al-tonno.html"
|
||||
"2022-09-27","martedì",,
|
||||
"2022-09-28","mercoledì",,
|
||||
"2022-09-28","mercoledì",,"https://ricette.giallozafferano.it/Orata-al-forno.html"
|
||||
"2022-09-29","giovedì",,
|
||||
"2022-09-30","venerdì",,
|
||||
"2022-10-01","sabato",,
|
||||
"2022-10-02","domenica",,
|
||||
"2022-10-02","domenica","https://ricette.giallozafferano.it/Gnocchi-alla-sorrentina.html",
|
||||
"2022-10-03","lunedì",,
|
||||
"2022-10-04","martedì",,
|
||||
"2022-10-04","martedì",,"https://ricette.giallozafferano.it/Spatzle-di-spinaci.html"
|
||||
"2022-10-05","mercoledì",,
|
||||
"2022-10-06","giovedì",,
|
||||
"2022-10-07","venerdì",,
|
||||
"2022-10-08","sabato",,
|
||||
"2022-10-06","giovedì",,"https://ricette.giallozafferano.it/Saltimbocca-alla-Romana.html"
|
||||
"2022-10-07","venerdì",,"https://ricette.giallozafferano.it/Risotto-ai-funghi.html"
|
||||
"2022-10-08","sabato","https://ricette.giallozafferano.it/Torta-Pasqualina.html",
|
||||
"2022-10-09","domenica",,
|
||||
"2022-10-10","lunedì",,
|
||||
"2022-10-10","lunedì",,"https://ricette.giallozafferano.it/Pennette-con-speck-e-zucchine.html"
|
||||
"2022-10-11","martedì",,
|
||||
"2022-10-12","mercoledì",,
|
||||
"2022-10-13","giovedì",,
|
||||
"2022-10-14","venerdì",,
|
||||
"2022-10-14","venerdì",,"https://ricette.giallozafferano.it/Polpette-al-sugo.html"
|
||||
"2022-10-15","sabato",,
|
||||
"2022-10-16","domenica",,
|
||||
"2022-10-17","lunedì",,
|
||||
"2022-10-18","martedì",,
|
||||
"2022-10-19","mercoledì",,
|
||||
"2022-10-19","mercoledì",,"https://ricette.giallozafferano.it/Scaloppine-ai-funghi.html"
|
||||
"2022-10-20","giovedì",,
|
||||
"2022-10-21","venerdì",,
|
||||
"2022-10-22","sabato",,
|
||||
"2022-10-22","sabato","https://ricette.giallozafferano.it/Gnudi.html",
|
||||
"2022-10-23","domenica",,
|
||||
"2022-10-24","lunedì",,
|
||||
"2022-10-25","martedì",,
|
||||
"2022-10-26","mercoledì",,
|
||||
"2022-10-27","giovedì",,
|
||||
"2022-10-28","venerdì",,
|
||||
"2022-10-29","sabato",,
|
||||
"2022-10-28","venerdì",,"https://ricette.giallozafferano.it/Vellutata-di-zucca-e-carote.html"
|
||||
"2022-10-29","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-10-30","domenica",,
|
||||
"2022-10-31","lunedì",,
|
||||
"2022-11-01","martedì",,
|
||||
"2022-11-02","mercoledì",,
|
||||
"2022-11-03","giovedì",,
|
||||
"2022-11-04","venerdì",,
|
||||
"2022-11-05","sabato",,
|
||||
"2022-11-05","sabato","https://ricette.giallozafferano.it/Spatzle-di-spinaci.html",
|
||||
"2022-11-06","domenica",,
|
||||
"2022-11-07","lunedì",,
|
||||
"2022-11-08","martedì",,
|
||||
"2022-11-09","mercoledì",,
|
||||
"2022-11-10","giovedì",,
|
||||
"2022-11-11","venerdì",,
|
||||
"2022-11-12","sabato",,
|
||||
"2022-11-11","venerdì",,"https://ricette.giallozafferano.it/Vellutata-di-porri-con-crostini-saporiti.html"
|
||||
"2022-11-12","sabato",,"https://ricette.giallozafferano.it/Chili-con-carne.html"
|
||||
"2022-11-13","domenica",,
|
||||
"2022-11-14","lunedì",,
|
||||
"2022-11-15","martedì",,
|
||||
"2022-11-16","mercoledì",,
|
||||
"2022-11-17","giovedì",,
|
||||
"2022-11-18","venerdì",,
|
||||
"2022-11-18","venerdì",,"https://ricette.giallozafferano.it/Torta-rustica.html"
|
||||
"2022-11-19","sabato",,
|
||||
"2022-11-20","domenica",,
|
||||
"2022-11-21","lunedì",,
|
||||
"2022-11-22","martedì",,
|
||||
"2022-11-23","mercoledì",,
|
||||
"2022-11-24","giovedì",,
|
||||
"2022-11-25","venerdì",,
|
||||
"2022-11-26","sabato",,
|
||||
"2022-11-25","venerdì",,"https://ricette.giallozafferano.it/Vellutata-di-zucca-e-carote.html"
|
||||
"2022-11-26","sabato","https://ricette.giallozafferano.it/Orata-al-forno.html",
|
||||
"2022-11-27","domenica",,
|
||||
"2022-11-28","lunedì",,
|
||||
"2022-11-29","martedì",,
|
||||
"2022-11-29","martedì",,"https://ricette.giallozafferano.it/Scaloppine-ai-funghi.html"
|
||||
"2022-11-30","mercoledì",,
|
||||
"2022-12-01","giovedì",,
|
||||
"2022-12-02","venerdì",,
|
||||
"2022-12-03","sabato",,
|
||||
"2022-12-04","domenica",,
|
||||
"2022-12-05","lunedì",,
|
||||
"2022-12-05","lunedì",,"https://ricette.giallozafferano.it/Spatzle-di-spinaci.html"
|
||||
"2022-12-06","martedì",,
|
||||
"2022-12-07","mercoledì",,
|
||||
"2022-12-08","giovedì",,
|
||||
"2022-12-09","venerdì",,
|
||||
"2022-12-10","sabato",,
|
||||
"2022-12-10","sabato","https://ricette.giallozafferano.it/Gnudi.html",
|
||||
"2022-12-11","domenica",,
|
||||
"2022-12-12","lunedì",,
|
||||
"2022-12-13","martedì",,
|
||||
"2022-12-14","mercoledì",,
|
||||
"2022-12-15","giovedì",,
|
||||
"2022-12-14","mercoledì",,"https://ricette.giallozafferano.it/Risotto-ai-funghi.html"
|
||||
"2022-12-15","giovedì",,"https://ricette.giallozafferano.it/Vellutata-di-porri-con-crostini-saporiti.html"
|
||||
"2022-12-16","venerdì",,
|
||||
"2022-12-17","sabato",,
|
||||
"2022-12-18","domenica",,
|
||||
"2022-12-18","domenica","https://ricette.giallozafferano.it/Polpette-al-sugo.html",
|
||||
"2022-12-19","lunedì",,
|
||||
"2022-12-20","martedì",,
|
||||
"2022-12-21","mercoledì",,
|
||||
"2022-12-22","giovedì",,
|
||||
"2022-12-23","venerdì",,
|
||||
"2022-12-24","sabato",,
|
||||
"2022-12-25","domenica",,
|
||||
"2022-12-25","domenica","https://ricette.giallozafferano.it/Filetto-in-crosta.html",
|
||||
"2022-12-26","lunedì",,
|
||||
"2022-12-27","martedì",,
|
||||
"2022-12-28","mercoledì",,
|
||||
"2022-12-28","mercoledì",,"https://ricette.giallozafferano.it/Orata-al-forno.html"
|
||||
"2022-12-29","giovedì",,
|
||||
"2022-12-30","venerdì",,
|
||||
"2022-12-31","sabato",,
|
||||
"2022-12-31","sabato",,
|
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
use {
|
||||
crate::config::Config, crate::constants, anyhow::anyhow, anyhow::Result,
|
||||
base64::write::EncoderWriter as Base64Encoder, reqwest::Url, std::io::Write,
|
||||
base64::write::EncoderWriter as Base64Encoder, chrono::DateTime, icalendar::CalendarComponent,
|
||||
reqwest::Url, std::io::Write, std::ops::Range, std::sync::Arc, tokio::sync::Semaphore,
|
||||
};
|
||||
|
||||
pub struct ApiClient {
|
||||
rest: reqwest::Client,
|
||||
agent: ureq::Agent,
|
||||
pub(crate) rest_semaphore: Arc<Semaphore>, // TODO: wrap in dereferentiable struct
|
||||
base_url: Url,
|
||||
caldav_base_url: Url,
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
|
@ -59,9 +59,8 @@ impl ApiClient {
|
|||
base_url,
|
||||
caldav_base_url,
|
||||
username: server.login_name.clone(),
|
||||
password: server.password.clone(),
|
||||
rest: rest_client,
|
||||
agent: ureq::Agent::new(),
|
||||
rest_semaphore: Arc::new(Semaphore::new(5)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -73,31 +72,105 @@ impl ApiClient {
|
|||
&self.base_url
|
||||
}
|
||||
|
||||
pub fn caldav_base_url(&self) -> &Url {
|
||||
&self.caldav_base_url
|
||||
}
|
||||
|
||||
pub fn username(&self) -> &str {
|
||||
&self.username
|
||||
}
|
||||
|
||||
pub fn get_calendars(
|
||||
pub async fn get_events<Tz>(
|
||||
&self,
|
||||
) -> core::result::Result<Vec<minicaldav::Calendar>, minicaldav::Error> {
|
||||
minicaldav::get_calendars(
|
||||
self.agent.clone(),
|
||||
self.username(),
|
||||
&self.password,
|
||||
&self.caldav_base_url,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_events(
|
||||
&self,
|
||||
calendar: &minicaldav::Calendar,
|
||||
) -> core::result::Result<(Vec<minicaldav::Event>, Vec<minicaldav::Error>), minicaldav::Error>
|
||||
calendar_name: &str,
|
||||
date_range: Range<DateTime<Tz>>,
|
||||
) -> Result<Vec<icalendar::Event>>
|
||||
where
|
||||
Tz: chrono::TimeZone,
|
||||
Tz::Offset: std::fmt::Display,
|
||||
{
|
||||
minicaldav::get_events(
|
||||
self.agent.clone(),
|
||||
self.username(),
|
||||
&self.password,
|
||||
calendar,
|
||||
)
|
||||
let report_method = reqwest::Method::from_bytes(b"REPORT").unwrap();
|
||||
let events_xml = self
|
||||
.rest()
|
||||
.request(
|
||||
report_method,
|
||||
// TODO extract into helper method
|
||||
self.caldav_base_url.join(&format!(
|
||||
"calendars/{}/{}",
|
||||
self.username(),
|
||||
calendar_name.to_lowercase().replace(" ", "-")
|
||||
))?,
|
||||
)
|
||||
.header("Prefer", "return-minimal")
|
||||
.header("Content-Type", "application/xml; charset=utf-8")
|
||||
.header("Depth", 1)
|
||||
.body(format!(
|
||||
"<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">
|
||||
<d:prop>
|
||||
<c:calendar-data />
|
||||
</d:prop>
|
||||
<c:filter>
|
||||
<c:comp-filter name=\"VCALENDAR\">
|
||||
<c:prop-filter name=\"PRODID\">
|
||||
<c:text-match>{}</c:text-match>
|
||||
</c:prop-filter>
|
||||
<c:comp-filter name=\"VEVENT\">
|
||||
<c:prop-filter name=\"DTSTART\">
|
||||
<time-range start=\"{}\" end=\"{}\" />
|
||||
</c:prop-filter>
|
||||
</c:comp-filter>
|
||||
</c:comp-filter>
|
||||
</c:filter>
|
||||
</c:calendar-query>
|
||||
",
|
||||
constants::CALENDAR_PROVIDER,
|
||||
date_range
|
||||
.start
|
||||
.naive_utc()
|
||||
.format(constants::ICAL_UTCTIME_FMT)
|
||||
.to_string(),
|
||||
date_range
|
||||
.end
|
||||
.naive_utc()
|
||||
.format(constants::ICAL_UTCTIME_FMT)
|
||||
.to_string()
|
||||
))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
let xml_doc = libxml::parser::Parser::default().parse_string(events_xml.as_bytes())?;
|
||||
let mut xpath_ctx = libxml::xpath::Context::new(&xml_doc).unwrap();
|
||||
xpath_ctx
|
||||
.register_namespace("cal", "urn:ietf:params:xml:ns:caldav")
|
||||
.unwrap();
|
||||
let calendars_txt = xpath_ctx
|
||||
.findnodes("//cal:calendar-data/text()", None)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|n| icalendar::parser::unfold(&n.get_content()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let calendars = calendars_txt
|
||||
.iter()
|
||||
.map(|cal| icalendar::parser::read_calendar(cal).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
let events = calendars
|
||||
.into_iter()
|
||||
.flat_map(|cal| {
|
||||
cal.components
|
||||
.into_iter()
|
||||
.filter(|comp| comp.name == "VEVENT")
|
||||
})
|
||||
.map(|comp| {
|
||||
let event: CalendarComponent = comp.into();
|
||||
match event {
|
||||
CalendarComponent::Event(e) => e,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(events.collect::<Vec<_>>())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use {
|
||||
crate::api_client::ApiClient,
|
||||
crate::recipe::{Ingredient, Recipe},
|
||||
anyhow::{anyhow, Result},
|
||||
chrono::{Duration, Local},
|
||||
icalendar::Component,
|
||||
regex::Regex,
|
||||
reqwest::{Method, StatusCode},
|
||||
std::collections::HashSet,
|
||||
std::ops::Range,
|
||||
};
|
||||
|
||||
pub async fn with(
|
||||
api_client: &ApiClient,
|
||||
calendar_name: &str,
|
||||
location: &str,
|
||||
days: u32,
|
||||
) -> Result<()> {
|
||||
let ids = map_events_to_recipe_ids(api_client, calendar_name, days).await?;
|
||||
let ingredients = get_ingredients(api_client, ids).await?;
|
||||
let ingredients = merge_ingredients(ingredients);
|
||||
let md = prepare_grocery_list(&ingredients)?;
|
||||
log::debug!("Saving the following grocery list:\n\n{}", &md);
|
||||
save_grocery_list(api_client, location, &md).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn map_events_to_recipe_ids(
|
||||
api_client: &ApiClient,
|
||||
calendar_name: &str,
|
||||
days: u32,
|
||||
) -> Result<HashSet<usize>> {
|
||||
let date_range = Range {
|
||||
start: Local::now(),
|
||||
end: Local::now() + Duration::days(days as i64),
|
||||
};
|
||||
|
||||
let all_events = api_client.get_events(calendar_name, date_range).await?;
|
||||
|
||||
let recipe_id_regex: Regex = Regex::new(r"cookbook@(\d+)").unwrap();
|
||||
let recipe_ids = all_events
|
||||
.iter()
|
||||
.flat_map(|event| event.property_value("DESCRIPTION"))
|
||||
.flat_map(|descr| recipe_id_regex.captures(descr))
|
||||
.flat_map(|c| c.get(1))
|
||||
.flat_map(|m| m.as_str().parse::<usize>())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
Ok(recipe_ids)
|
||||
}
|
||||
|
||||
async fn get_ingredients<RecipeIds>(
|
||||
api_client: &ApiClient,
|
||||
recipe_ids: RecipeIds,
|
||||
) -> Result<Vec<Ingredient>>
|
||||
where
|
||||
RecipeIds: IntoIterator<Item = usize>,
|
||||
{
|
||||
let ingredients = recipe_ids.into_iter().map(|id: usize| async move {
|
||||
// TODO code duplicated with schedule_csv::get_all_recipes
|
||||
let recipe_url = format!("apps/cookbook/api/recipes/{id}");
|
||||
let response = api_client
|
||||
.rest()
|
||||
.get(api_client.base_url().join(&recipe_url).unwrap())
|
||||
.send()
|
||||
.await
|
||||
.expect(&format!("Cannot fetch recipe with id {}", id));
|
||||
|
||||
response.json::<Recipe>().await.map(|r| {
|
||||
log::info!("Retrieved ingredients for '{}'", r.name);
|
||||
r.ingredients
|
||||
})
|
||||
});
|
||||
|
||||
let ingredients = futures::future::try_join_all(ingredients).await?;
|
||||
Ok(ingredients.into_iter().flatten().collect())
|
||||
}
|
||||
|
||||
fn merge_ingredients(mut ingredients: Vec<Ingredient>) -> Vec<Ingredient> {
|
||||
ingredients.sort();
|
||||
|
||||
// TODO actual merging
|
||||
|
||||
ingredients
|
||||
}
|
||||
|
||||
fn prepare_grocery_list(ingredients: &Vec<Ingredient>) -> Result<String> {
|
||||
let mut out = String::new();
|
||||
use std::fmt::Write;
|
||||
|
||||
writeln!(
|
||||
out,
|
||||
"# Grocery list - {}",
|
||||
chrono::Local::now().format("%Y-%m-%d").to_string()
|
||||
)?;
|
||||
writeln!(out)?; // leave an empty line
|
||||
for ingredient in ingredients {
|
||||
let ingredient = ingredient.0.as_str();
|
||||
writeln!(out, "- [ ] {}", ingredient)?;
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
async fn save_grocery_list(api_client: &ApiClient, filename: &str, contents: &str) -> Result<()> {
|
||||
let dav_base_url = api_client
|
||||
.base_url()
|
||||
.join(&format!("remote.php/dav/files/{}/", api_client.username()))?;
|
||||
|
||||
let filename_components = filename.split('/').collect::<Vec<_>>();
|
||||
filename_components
|
||||
.iter()
|
||||
.take(filename_components.len() - 1)
|
||||
.fold(Ok(dav_base_url.clone()), |url, dir| {
|
||||
url.map(|u| u.join(&format!("{dir}/")).unwrap())
|
||||
.and_then(|url| {
|
||||
futures::executor::block_on(async {
|
||||
let response = api_client
|
||||
.rest()
|
||||
.request(Method::from_bytes(b"MKCOL").unwrap(), url.clone())
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match response.map(|r| r.status()) {
|
||||
Ok(StatusCode::OK)
|
||||
| Ok(StatusCode::METHOD_NOT_ALLOWED /* already exists */) => Ok(url),
|
||||
Ok(status) => Err(anyhow!(
|
||||
"Could not create WebDAV collection {}, server responded with {}",
|
||||
&url,
|
||||
status
|
||||
)),
|
||||
Err(e) => Err(anyhow!(e)),
|
||||
}
|
||||
})
|
||||
})
|
||||
})?;
|
||||
|
||||
let file_url = dav_base_url.join(filename).unwrap();
|
||||
log::info!("Saving grocery list to {}", &file_url);
|
||||
let response = api_client
|
||||
.rest()
|
||||
.put(file_url.clone())
|
||||
.header("Content-Type", "text/markdown; charset=utf-8")
|
||||
.body(contents.to_owned())
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
match response.status() {
|
||||
StatusCode::CREATED | StatusCode::NO_CONTENT => Ok(()),
|
||||
status => Err(anyhow!(
|
||||
"Cannot save grocery list at {}, server responded with status {}",
|
||||
file_url,
|
||||
status
|
||||
)),
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ where
|
|||
response.status()
|
||||
);
|
||||
}
|
||||
log::info!("Imported recipe into cookbook: {}", url.as_ref());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
pub mod groceries;
|
||||
pub mod import;
|
||||
pub mod init;
|
||||
pub mod purge;
|
||||
pub mod schedule;
|
||||
pub mod schedule_csv;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use {crate::api_client::ApiClient, crate::constants, anyhow::Result, reqwest::Method};
|
||||
|
||||
pub async fn with(api_client: &ApiClient, calendar_name: &str) -> Result<()> {
|
||||
let report_method = Method::from_bytes(b"REPORT")?;
|
||||
let events_xml = api_client
|
||||
.rest()
|
||||
.request(
|
||||
report_method,
|
||||
// TODO extract into helper method
|
||||
api_client.caldav_base_url().join(&format!(
|
||||
"calendars/{}/{}/",
|
||||
api_client.username(),
|
||||
calendar_name.to_lowercase().replace(" ", "-")
|
||||
))?,
|
||||
)
|
||||
.header("Prefer", "return-minimal")
|
||||
.header("Content-Type", "application/xml; charset=utf-8")
|
||||
.header("Depth", 1)
|
||||
.body(format!(
|
||||
"<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">
|
||||
<d:prop>
|
||||
<d:getetag/>
|
||||
</d:prop>
|
||||
<c:filter>
|
||||
<c:comp-filter name=\"VCALENDAR\">
|
||||
<c:prop-filter name=\"PRODID\">
|
||||
<c:text-match>{}</c:text-match>
|
||||
</c:prop-filter>
|
||||
</c:comp-filter>
|
||||
</c:filter>
|
||||
</c:calendar-query>
|
||||
",
|
||||
constants::CALENDAR_PROVIDER,
|
||||
))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
let xml_doc = libxml::parser::Parser::default().parse_string(events_xml.as_bytes())?;
|
||||
let mut xpath_ctx = libxml::xpath::Context::new(&xml_doc).unwrap();
|
||||
xpath_ctx.register_namespace("d", "DAV:").unwrap();
|
||||
let events_to_purge = xpath_ctx
|
||||
.findnodes("//d:response/d:href/text()", None)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|n| icalendar::parser::unfold(&n.get_content()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for url in events_to_purge {
|
||||
api_client
|
||||
.rest()
|
||||
.delete(api_client.base_url().join(&url)?)
|
||||
.send()
|
||||
.await?;
|
||||
log::debug!("Purged {}", &url);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -4,9 +4,9 @@
|
|||
use {
|
||||
crate::api_client::ApiClient,
|
||||
crate::commands::import,
|
||||
crate::constants,
|
||||
crate::event::{Event, Meal},
|
||||
crate::recipe,
|
||||
crate::{constants, helpers},
|
||||
anyhow::{bail, Result},
|
||||
chrono::naive::NaiveDate,
|
||||
futures::future::try_join_all,
|
||||
|
@ -31,6 +31,9 @@ pub async fn with(api_client: &ApiClient, calendar: &str, csv_file: &Path) -> Re
|
|||
|
||||
let recipe_urls = urls_from_csv(records.iter())?;
|
||||
import::with(&api_client, recipe_urls.into_iter()).await?;
|
||||
|
||||
// Unfortunately, Nextcloud Cookbook doesn't return an id for imported recipes,
|
||||
// so we have to resort to fetch all of them to match them
|
||||
let recipes = get_all_recipes(&api_client).await?;
|
||||
|
||||
let events = records
|
||||
|
@ -70,6 +73,7 @@ where
|
|||
}
|
||||
|
||||
async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<recipe::Recipe>>> {
|
||||
log::info!("Getting list of all recipes");
|
||||
let metadata = api_client
|
||||
.rest()
|
||||
.get(api_client.base_url().join("apps/cookbook/api/recipes")?)
|
||||
|
@ -93,6 +97,7 @@ async fn get_all_recipes(api_client: &ApiClient) -> Result<HashMap<String, Rc<re
|
|||
"Cannot fetch recipe {} with id {}",
|
||||
rm.name, rm.id
|
||||
));
|
||||
|
||||
response.json::<recipe::Recipe>().await.map(|r| Rc::new(r))
|
||||
});
|
||||
|
||||
|
@ -110,42 +115,58 @@ async fn publish_events<'a, EventsIter>(
|
|||
where
|
||||
EventsIter: Iterator<Item = Event>,
|
||||
{
|
||||
let calendar_prototype: ics::ICalendar = ics::ICalendar::new(
|
||||
"2.0",
|
||||
format!(
|
||||
"-//IDN {}//{} {}//EN",
|
||||
constants::VENDOR,
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION")
|
||||
),
|
||||
);
|
||||
|
||||
let dav_base = api_client
|
||||
.rest()
|
||||
.head(api_client.base_url().join("/.well-known/caldav")?)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let calendar_url = dav_base.url().join(&format!(
|
||||
let calendar_url = api_client.caldav_base_url().join(&format!(
|
||||
"calendars/{}/{}/",
|
||||
&api_client.username(),
|
||||
calendar.to_lowercase().as_str().replace(" ", "-")
|
||||
))?;
|
||||
|
||||
let calendar_prototype = &calendar_prototype;
|
||||
let calendar_url = &calendar_url;
|
||||
let update_requests = events.map(|ev| async move {
|
||||
let url = calendar_url.join(&format!("{}.ics", ev.uid)).unwrap();
|
||||
let mut cal = calendar_prototype.clone();
|
||||
cal.add_event(ev.into());
|
||||
let alarm_text_repr = format!(
|
||||
"BEGIN:VALARM\nACTION:DISPLAY\nTRIGGER:-PT15M\nDESCRIPTION:{}\nEND:VALARM",
|
||||
&helpers::ical_escape_text(&ev.recipe.name)
|
||||
);
|
||||
|
||||
api_client
|
||||
let info_message = format!(
|
||||
"Saving event at {} for '{}'",
|
||||
&ev.ends_at.date(),
|
||||
&ev.recipe.name
|
||||
);
|
||||
let cal = icalendar::Calendar::new()
|
||||
.push::<icalendar::Event>(ev.into())
|
||||
.done();
|
||||
|
||||
let cal_as_string = (&cal.to_string())
|
||||
.replacen(
|
||||
// need to hack around inability to set PRODID in icalendar::Calendar
|
||||
"PRODID:ICALENDAR-RS",
|
||||
&format!("PRODID:{}", constants::CALENDAR_PROVIDER),
|
||||
1,
|
||||
)
|
||||
.replacen(
|
||||
// need to hack around inability to set VALARM in icalendar::Event
|
||||
"END:VEVENT",
|
||||
&format!("{}\nEND:VEVENT", alarm_text_repr),
|
||||
1,
|
||||
);
|
||||
|
||||
// TODO: wrap this
|
||||
let _ = api_client.rest_semaphore.acquire().await.unwrap();
|
||||
let response = api_client
|
||||
.rest()
|
||||
.put(url)
|
||||
.header("Content-Type", "text/calendar; charset=utf-8")
|
||||
.body(cal.to_string())
|
||||
.body(cal_as_string)
|
||||
.send()
|
||||
.await
|
||||
.await;
|
||||
|
||||
log::info!("{}", info_message);
|
||||
|
||||
// TODO: magic numbers are bad...
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
response
|
||||
});
|
||||
|
||||
let responses = try_join_all(update_requests).await?;
|
||||
|
|
|
@ -2,4 +2,9 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
pub const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
|
||||
pub const VENDOR: &str = "montecristosoftware.eu";
|
||||
pub const CALENDAR_PROVIDER: &str = concat!(
|
||||
"-//IDN montecristosoftware.eu//",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"//EN"
|
||||
);
|
||||
pub const ICAL_UTCTIME_FMT: &str = "%Y%m%dT%H%M%SZ";
|
||||
|
|
83
src/event.rs
83
src/event.rs
|
@ -3,10 +3,8 @@
|
|||
|
||||
use {
|
||||
crate::recipe::Recipe,
|
||||
chrono::{DateTime, Datelike, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc},
|
||||
ics::escape_text,
|
||||
ics::properties as calprop,
|
||||
ics::Event as CalEvent,
|
||||
chrono::{/*Datelike, */ NaiveDate, NaiveDateTime, NaiveTime, Utc},
|
||||
icalendar::Event as CalEvent,
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -46,55 +44,40 @@ impl Event {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Event> for CalEvent<'a> {
|
||||
impl From<Event> for CalEvent {
|
||||
fn from(ev: Event) -> Self {
|
||||
let start_time = Local
|
||||
.from_local_datetime(&(*&ev.ends_at - ev.recipe.total_time()))
|
||||
.unwrap();
|
||||
let end_time = Local.from_local_datetime(&ev.ends_at).unwrap();
|
||||
let timezone = iana_time_zone::get_timezone().unwrap();
|
||||
use icalendar::Component;
|
||||
|
||||
let mut event = ics::Event::new(ev.uid.clone(), dt_utc_fmt(&Utc::now()));
|
||||
event.push(calprop::Summary::new(escape_text(ev.recipe.name.clone())));
|
||||
event.push(calprop::Description::new(format!(
|
||||
"cookbook@{}",
|
||||
ev.recipe.id
|
||||
)));
|
||||
event.push(calprop::Location::new(escape_text(ev.recipe.url.clone())));
|
||||
// const DAY_NAMES: [&str; 7] = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
|
||||
let start_time = ev.ends_at - ev.recipe.total_time();
|
||||
|
||||
let mut dtstart = calprop::DtStart::new(dt_fmt(&start_time));
|
||||
dtstart.append(ics::parameters!("TZID" => timezone.clone()));
|
||||
event.push(dtstart);
|
||||
let cal_event = CalEvent::new()
|
||||
.uid(&ev.uid)
|
||||
.summary(&ev.recipe.name)
|
||||
.description(&format!("cookbook@{}", ev.recipe.id))
|
||||
.location(&ev.recipe.url)
|
||||
.timestamp(Utc::now())
|
||||
.starts(start_time)
|
||||
.ends(ev.ends_at)
|
||||
/* FIXME
|
||||
.add_property(
|
||||
// TODO make configurable yearly repetition, for now this suits my personal uses
|
||||
"RRULE",
|
||||
&format!(
|
||||
"FREQ=YEARLY;BYDAY={weekday};BYWEEKNO={weekno}",
|
||||
weekday = DAY_NAMES
|
||||
.get(start_time.weekday().num_days_from_monday() as usize)
|
||||
.unwrap(),
|
||||
weekno = start_time.iso_week().week(),
|
||||
),
|
||||
)*/
|
||||
.add_property(
|
||||
// TODO make configurable yearly repetition, for now this suits my personal uses
|
||||
"RRULE",
|
||||
"FREQ=YEARLY",
|
||||
)
|
||||
.done();
|
||||
|
||||
let mut dtend = calprop::DtEnd::new(dt_fmt(&end_time));
|
||||
dtend.append(ics::parameters!("TZID" => timezone));
|
||||
event.push(dtend);
|
||||
|
||||
// TODO make configurable yearly repetition, for now this suits my personal uses
|
||||
const DAY_NAMES: [&str; 7] = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
|
||||
event.push(calprop::RRule::new(format!(
|
||||
"FREQ=YEARLY;BYDAY={weekday};BYWEEKNO={weekno}",
|
||||
weekday = DAY_NAMES
|
||||
.get(start_time.weekday().num_days_from_monday() as usize)
|
||||
.unwrap(),
|
||||
weekno = start_time.iso_week().week(),
|
||||
)));
|
||||
|
||||
let mut trigger = calprop::Trigger::new("-PT15M");
|
||||
trigger.append(ics::parameters!("RELATED" => "START"));
|
||||
let alarm = ics::Alarm::display(
|
||||
trigger,
|
||||
calprop::Description::new(escape_text(ev.recipe.name.clone())),
|
||||
);
|
||||
event.add_alarm(alarm);
|
||||
event
|
||||
cal_event
|
||||
}
|
||||
}
|
||||
|
||||
fn dt_fmt(datetime: &DateTime<Local>) -> String {
|
||||
datetime.format("%Y%m%dT%H%M%S").to_string()
|
||||
}
|
||||
|
||||
fn dt_utc_fmt(datetime: &DateTime<Utc>) -> String {
|
||||
datetime.format("%Y%m%dT%H%M%SZ").to_string()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: 2022 Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
pub fn ical_escape_text(text: &str) -> String {
|
||||
/* https://www.kanzaki.com/docs/ical/text.html
|
||||
|
||||
The "TEXT" property values may also contain special characters that
|
||||
are used to signify delimiters, such as a COMMA character for lists of
|
||||
values or a SEMICOLON character for structured values. In order to
|
||||
support the inclusion of these special characters in "TEXT" property
|
||||
values, they MUST be escaped with a BACKSLASH character. A BACKSLASH
|
||||
character (US-ASCII decimal 92) in a "TEXT" property value MUST be
|
||||
escaped with another BACKSLASH character. A COMMA character in a "TEXT"
|
||||
property value MUST be escaped with a BACKSLASH character
|
||||
(US-ASCII decimal 92). A SEMICOLON character in a "TEXT" property
|
||||
value MUST be escaped with a BACKSLASH character (US-ASCII decimal
|
||||
92). However, a COLON character in a "TEXT" property value SHALL
|
||||
NOT be escaped with a BACKSLASH character.
|
||||
*/
|
||||
|
||||
let mut out = Vec::<u8>::with_capacity(text.len());
|
||||
for c in text.as_bytes() {
|
||||
match c {
|
||||
b'\\' => out.extend_from_slice(&[b'\\', b'\\']),
|
||||
b',' => out.extend_from_slice(&[b'\\', b',']),
|
||||
b';' => out.extend_from_slice(&[b'\\', b';']),
|
||||
_ => out.push(*c),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { String::from_utf8_unchecked(out) }
|
||||
}
|
42
src/main.rs
42
src/main.rs
|
@ -6,6 +6,7 @@ mod commands;
|
|||
mod config;
|
||||
mod constants;
|
||||
mod event;
|
||||
mod helpers;
|
||||
mod recipe;
|
||||
|
||||
use {
|
||||
|
@ -18,6 +19,8 @@ use {
|
|||
|
||||
#[tokio::main(flavor = "multi_thread")]
|
||||
async fn main() -> Result<()> {
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
|
||||
|
||||
let args = setup_args();
|
||||
parse_args(&args).await
|
||||
}
|
||||
|
@ -41,10 +44,21 @@ fn setup_args() -> ArgMatches {
|
|||
.arg(arg!(<url> ... "One or more URLs each pointing to page with a recipe to import in NextCloud")),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("schedule")
|
||||
.about("")
|
||||
Command::new("groceries")
|
||||
.about("Create a grocery list from scheduled calendar events")
|
||||
.arg(server_arg.clone())
|
||||
.arg(arg!(-d --days <days> "")
|
||||
.arg(arg!(<calendar_name> "The name of the calendar to read from for scheduled recipes"))
|
||||
.arg(arg!(<filename> "The relative path for the Markdown file that will be saved on the server. Recommended ending it in '.md'."))
|
||||
.arg(arg!(-d --days <days> "Number of days in the future to consider")
|
||||
.value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..))
|
||||
.required(false)
|
||||
.default_value("7"))
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("schedule")
|
||||
.about("TODO; not implemented yet (pick automatically recipes and create calendar events for them)")
|
||||
.arg(server_arg.clone())
|
||||
.arg(arg!(-d --days <days> "Number of days to schedule")
|
||||
.value_parser(clap::builder::RangedU64ValueParser::<u32>::new().range(1..))
|
||||
.required(false)
|
||||
.default_value("7"))
|
||||
|
@ -56,6 +70,12 @@ fn setup_args() -> ArgMatches {
|
|||
.arg(arg!(<calendar_name> ""))
|
||||
.arg(arg!(<csv_file> "").value_parser(clap::value_parser!(PathBuf)))
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("purge")
|
||||
.about("Removes all events created by this application from a given calendar")
|
||||
.arg(server_arg.clone())
|
||||
.arg(arg!(<calendar_name> ""))
|
||||
)
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
|
@ -77,6 +97,15 @@ async fn parse_args(args: &ArgMatches) -> Result<()> {
|
|||
.map(|s| s.as_str());
|
||||
commands::import::with(&api_client, urls).await
|
||||
}
|
||||
Some(("groceries", sub_matches)) => {
|
||||
let api_client = get_api_client(&sub_matches, &configuration)?;
|
||||
let calendar_name = sub_matches
|
||||
.get_one::<String>("calendar_name")
|
||||
.expect("<calendar_name> is a mandatory parameter, it cannot be missing");
|
||||
let days = sub_matches.get_one::<u32>("days").unwrap();
|
||||
let filename = sub_matches.get_one::<String>("filename").unwrap();
|
||||
commands::groceries::with(&api_client, calendar_name.as_str(), filename, *days).await
|
||||
}
|
||||
Some(("schedule", sub_matches)) => {
|
||||
let api_client = get_api_client(&sub_matches, &configuration)?;
|
||||
commands::schedule::with(&api_client).await
|
||||
|
@ -91,6 +120,13 @@ async fn parse_args(args: &ArgMatches) -> Result<()> {
|
|||
.expect("<calendar_name> is a mandatory parameter, it cannot be missing");
|
||||
commands::schedule_csv::with(&api_client, calendar_name.as_str(), &csv_file).await
|
||||
}
|
||||
Some(("purge", sub_matches)) => {
|
||||
let api_client = get_api_client(&sub_matches, &configuration)?;
|
||||
let calendar_name = sub_matches
|
||||
.get_one::<String>("calendar_name")
|
||||
.expect("<calendar_name> is a mandatory parameter, it cannot be missing");
|
||||
commands::purge::with(&api_client, calendar_name.as_str()).await
|
||||
}
|
||||
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,17 +60,17 @@ pub struct Recipe {
|
|||
//pub nutrition: Nutrition,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[derive(Deserialize, Debug, Ord, Eq, PartialEq, PartialOrd)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Ingredient(String);
|
||||
pub struct Ingredient(pub String);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Tool(String);
|
||||
pub struct Tool(pub String);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Instruction(String);
|
||||
pub struct Instruction(pub String);
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
Loading…
Reference in New Issue