Compare commits

..

17 Commits

Author SHA1 Message Date
Lennart
283be0a26c version 0.4.5 2025-06-27 17:40:48 +02:00
Lennart
1060625b9d fix(oidc): Fix login not working for missing groups claim
see #87
2025-06-27 17:38:42 +02:00
Lennart
86ae31e94c tiny steps towards unit testing for each resource 2025-06-27 14:33:25 +02:00
Lennart
e2f5773e3c Dockerfile: Target Rust 1.88 2025-06-27 14:32:08 +02:00
Lennart
b54fbebe7c store: test preparations 2025-06-27 13:58:14 +02:00
Lennart
fe78a82806 clippy appeasement 2025-06-27 13:57:57 +02:00
Lennart
22544b8c2f Justfile: Add commands to build frontend components 2025-06-27 13:57:44 +02:00
Lennart
340b99e491 Dockerfile: Fix llvm dependency for arm64 builds 2025-06-26 22:25:04 +02:00
Lennart
787ea90376 Dockerfile, update Rust to 1.87+ 2025-06-26 22:03:16 +02:00
Lennart
973a86f21a remove some disabled and broken tests 2025-06-26 19:42:06 +02:00
Lennart
39fc2fb55d principal_type refactoring 2025-06-26 12:50:37 +02:00
Lennart
ab4d763304 tiny improvements to documentation 2025-06-26 12:39:23 +02:00
Lennart
9cf74f7198 frontend: Explicitly mark collections from other groups 2025-06-25 16:14:55 +02:00
Lennart
2c2a6006c7 version 0.4.4 2025-06-25 16:03:31 +02:00
Lennart
4600f03b45 frontend: slight improvements to collection lists 2025-06-25 16:01:17 +02:00
Lennart
41fc1e6ea5 frontend: Remove default red for calendars without color 2025-06-25 15:56:46 +02:00
Lennart
b56591c482 frontend: LSP appeasement 2025-06-25 15:54:47 +02:00
46 changed files with 4354 additions and 4295 deletions

View File

@@ -2,3 +2,5 @@
indent_style = space
indent_size = 4
[docs/**/*.md]
indent_size = 4

268
Cargo.lock generated
View File

@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "adler2"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
@@ -49,9 +49,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.18"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -64,33 +64,33 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.8"
version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa"
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
"once_cell_polyfill",
@@ -162,9 +162,9 @@ dependencies = [
[[package]]
name = "askama_web"
version = "0.14.3"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a91fdeb04bf77d96234780cdd58fc221eb10de7031e1782a22f40fc8ac1a313"
checksum = "83731f1a2286209c2b679445e8faaa53270646a90c509bf92729e966d198cb6b"
dependencies = [
"askama",
"askama_web_derive",
@@ -206,9 +206,9 @@ dependencies = [
[[package]]
name = "atomic"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340"
dependencies = [
"bytemuck",
]
@@ -221,9 +221,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "axum"
@@ -379,15 +379,15 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.17.0"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytemuck"
version = "1.23.0"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
[[package]]
name = "byteorder"
@@ -403,18 +403,18 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cc"
version = "1.2.25"
version = "1.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "cfg_aliases"
@@ -469,9 +469,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.39"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
@@ -479,9 +479,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.39"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
@@ -491,9 +491,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.32"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck",
"proc-macro2",
@@ -503,15 +503,15 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "colorchoice"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "concurrent-queue"
@@ -1068,7 +1068,7 @@ dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi 0.11.1+wasi-snapshot-preview1",
"wasm-bindgen",
]
@@ -1136,9 +1136,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.3"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
dependencies = [
"allocator-api2",
"equivalent",
@@ -1151,7 +1151,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
dependencies = [
"hashbrown 0.15.3",
"hashbrown 0.15.4",
]
[[package]]
@@ -1295,9 +1295,9 @@ dependencies = [
[[package]]
name = "hyper-rustls"
version = "0.27.6"
version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
"http",
"hyper",
@@ -1325,9 +1325,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.13"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -1512,7 +1512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.3",
"hashbrown 0.15.4",
"serde",
]
@@ -1589,9 +1589,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.172"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libm"
@@ -1678,9 +1678,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.4"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "mime"
@@ -1700,9 +1700,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
@@ -1714,7 +1714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.59.0",
]
@@ -2370,9 +2370,9 @@ dependencies = [
[[package]]
name = "quinn-udp"
version = "0.5.12"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842"
checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970"
dependencies = [
"cfg_aliases",
"libc",
@@ -2393,9 +2393,9 @@ dependencies = [
[[package]]
name = "r-efi"
version = "5.2.0"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
@@ -2458,13 +2458,33 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.12"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
dependencies = [
"bitflags",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "regex"
version = "1.11.1"
@@ -2517,9 +2537,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
[[package]]
name = "reqwest"
version = "0.12.19"
version = "0.12.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119"
checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -2534,11 +2554,9 @@ dependencies = [
"hyper",
"hyper-rustls",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite",
"quinn",
@@ -2715,9 +2733,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustc-hash"
@@ -2736,7 +2754,7 @@ dependencies = [
[[package]]
name = "rustical"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"anyhow",
"argon2",
@@ -2779,7 +2797,7 @@ dependencies = [
[[package]]
name = "rustical_caldav"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"axum",
@@ -2798,6 +2816,7 @@ dependencies = [
"rustical_dav_push",
"rustical_ical",
"rustical_store",
"rustical_store_sqlite",
"rustical_xml",
"serde",
"sha2",
@@ -2814,7 +2833,7 @@ dependencies = [
[[package]]
name = "rustical_carddav"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"axum",
@@ -2846,7 +2865,7 @@ dependencies = [
[[package]]
name = "rustical_dav"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"axum",
@@ -2871,7 +2890,7 @@ dependencies = [
[[package]]
name = "rustical_dav_push"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"axum",
@@ -2897,7 +2916,7 @@ dependencies = [
[[package]]
name = "rustical_frontend"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"askama",
"askama_web",
@@ -2930,7 +2949,7 @@ dependencies = [
[[package]]
name = "rustical_ical"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"axum",
"chrono",
@@ -2948,7 +2967,7 @@ dependencies = [
[[package]]
name = "rustical_oidc"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"axum",
@@ -2963,7 +2982,7 @@ dependencies = [
[[package]]
name = "rustical_store"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"anyhow",
"async-trait",
@@ -2997,7 +3016,7 @@ dependencies = [
[[package]]
name = "rustical_store_sqlite"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"async-trait",
"chrono",
@@ -3017,7 +3036,7 @@ dependencies = [
[[package]]
name = "rustical_xml"
version = "0.4.3"
version = "0.4.5"
dependencies = [
"quick-xml",
"thiserror 2.0.12",
@@ -3026,9 +3045,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.27"
version = "0.23.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321"
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
dependencies = [
"once_cell",
"ring",
@@ -3080,6 +3099,18 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schemars"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -3169,9 +3200,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "0.6.8"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
@@ -3190,15 +3221,16 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.12.0"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.9.0",
"schemars",
"serde",
"serde_derive",
"serde_json",
@@ -3208,9 +3240,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.12.0"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77"
dependencies = [
"darling",
"proc-macro2",
@@ -3282,18 +3314,15 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
[[package]]
name = "smallvec"
version = "1.15.0"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
dependencies = [
"serde",
]
@@ -3357,7 +3386,7 @@ dependencies = [
"futures-intrusive",
"futures-io",
"futures-util",
"hashbrown 0.15.3",
"hashbrown 0.15.4",
"hashlink",
"indexmap 2.9.0",
"log",
@@ -3573,9 +3602,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.101"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@@ -3644,12 +3673,11 @@ dependencies = [
[[package]]
name = "thread_local"
version = "1.1.8"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
@@ -3774,9 +3802,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.22"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
@@ -3786,18 +3814,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.9"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.26"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap 2.9.0",
"serde",
@@ -3809,9 +3837,9 @@ dependencies = [
[[package]]
name = "toml_write"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "tonic"
@@ -3979,9 +4007,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.28"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
@@ -3990,9 +4018,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.33"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
"valuable",
@@ -4186,9 +4214,9 @@ dependencies = [
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
@@ -4298,9 +4326,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
dependencies = [
"rustls-pki-types",
]
@@ -4383,9 +4411,9 @@ dependencies = [
[[package]]
name = "windows-link"
version = "0.1.1"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-result"
@@ -4555,9 +4583,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.10"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
dependencies = [
"memchr",
]
@@ -4620,18 +4648,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -2,7 +2,7 @@
members = ["crates/*"]
[workspace.package]
version = "0.4.3"
version = "0.4.5"
edition = "2024"
description = "A CalDAV server"
repository = "https://github.com/lennart-k/rustical"

View File

@@ -1,11 +1,11 @@
FROM --platform=$BUILDPLATFORM rust:1.86-alpine AS chef
FROM --platform=$BUILDPLATFORM rust:1.88-alpine AS chef
ARG TARGETPLATFORM
ARG BUILDPLATFORM
# the compiler will otherwise ask for aarch64-linux-musl-gcc
ENV CC_aarch64_unknown_linux_musl="clang"
ENV AR_aarch64_unknown_linux_musl="llvm-ar"
ENV AR_aarch64_unknown_linux_musl="llvm20-ar"
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Clink-self-contained=yes -Clinker=rust-lld"
# Stupid workaound with tempfiles since environment variables
@@ -16,7 +16,7 @@ RUN case $TARGETPLATFORM in \
*) echo "Unsupported platform ${TARGETPLATFORM}"; exit 1;; \
esac
RUN apk add --no-cache musl-dev llvm19 clang perl pkgconf make \
RUN apk add --no-cache musl-dev llvm20 clang perl pkgconf make \
&& rustup target add "$(cat /tmp/rust_target)" \
&& cargo install cargo-chef --locked \
&& rm -rf "$CARGO_HOME/registry"

View File

@@ -1,2 +1,9 @@
licenses:
cargo about generate about.hbs > crates/frontend/public/assets/licenses.html
frontend-dev:
cd crates/frontend/js-components && deno task dev
frontend-build:
cd crates/frontend/js-components && deno task build

View File

@@ -7,6 +7,9 @@ repository.workspace = true
license.workspace = true
publish = false
[dev-dependencies]
rustical_store_sqlite = { workspace = true, features = ["test"] }
[dependencies]
axum.workspace = true
axum-extra.workspace = true

View File

@@ -11,8 +11,10 @@ mod service;
pub use service::*;
mod prop;
pub use prop::*;
#[cfg(test)]
pub mod tests;
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct PrincipalResource {
principal: Principal,
members: Vec<String>,

View File

@@ -0,0 +1,39 @@
use crate::principal::PrincipalResourceService;
use rustical_dav::resource::ResourceService;
use rustical_store::auth::{AuthenticationProvider, Principal, PrincipalType};
use rustical_store_sqlite::tests::get_test_stores;
#[tokio::test]
async fn test_principal_resource() {
let (_, cal_store, sub_store, auth_provider, _) = get_test_stores().await;
let service = PrincipalResourceService {
cal_store,
sub_store,
auth_provider: auth_provider.clone(),
};
auth_provider
.insert_principal(
Principal {
id: "user".to_owned(),
displayname: None,
memberships: vec![],
password: None,
principal_type: PrincipalType::Individual,
},
true,
)
.await
.unwrap();
assert!(matches!(
service.get_resource(&("anonymous".to_owned(),), true).await,
Err(crate::Error::NotFound)
));
let _principal_resource = service
.get_resource(&("user".to_owned(),), true)
.await
.unwrap();
}

View File

@@ -58,6 +58,7 @@ pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>(
Ok((result, not_found))
}
#[allow(clippy::too_many_arguments)]
pub async fn handle_addressbook_multiget<AS: AddressbookStore>(
addr_multiget: &AddressbookMultigetRequest,
prop: &PropfindType<AddressObjectPropWrapperName>,

View File

@@ -19,7 +19,7 @@ export class CreateAddressbookForm extends LitElement {
@property()
user: String = ''
@property()
id: String = ''
addr_id: String = ''
@property()
displayname: String = ''
@property()
@@ -36,7 +36,7 @@ export class CreateAddressbookForm extends LitElement {
<form @submit=${this.submit} ${ref(this.form)}>
<label>
id
<input type="text" name="id" @change=${e => this.id = e.target.value} />
<input type="text" name="id" @change=${e => this.addr_id = e.target.value} />
</label>
<br>
<label>
@@ -59,7 +59,7 @@ export class CreateAddressbookForm extends LitElement {
async submit(e: SubmitEvent) {
console.log(this.displayname)
e.preventDefault()
if (!this.id) {
if (!this.addr_id) {
alert("Empty id")
return
}
@@ -68,7 +68,7 @@ export class CreateAddressbookForm extends LitElement {
return
}
// TODO: Escape user input: There's not really a security risk here but would be nicer
await this.client.createDirectory(`/principal/${this.user}/${this.id}`, {
await this.client.createDirectory(`/principal/${this.user}/${this.addr_id}`, {
data: `
<mkcol xmlns="DAV:" xmlns:CARD="urn:ietf:params:xml:ns:carddav">
<set>

View File

@@ -7,7 +7,6 @@ import { createClient } from "webdav";
export class CreateCalendarForm extends LitElement {
constructor() {
super()
}
protected override createRenderRoot() {
@@ -19,7 +18,7 @@ export class CreateCalendarForm extends LitElement {
@property()
user: String = ''
@property()
id: String = ''
cal_id: String = ''
@property()
displayname: String = ''
@property()
@@ -43,7 +42,7 @@ export class CreateCalendarForm extends LitElement {
<form @submit=${this.submit} ${ref(this.form)}>
<label>
id
<input type="text" name="id" @change=${e => this.id = e.target.value} />
<input type="text" name="id" @change=${e => this.cal_id = e.target.value} />
</label>
<br>
<label>
@@ -83,7 +82,7 @@ export class CreateCalendarForm extends LitElement {
async submit(e: SubmitEvent) {
console.log(this.displayname)
e.preventDefault()
if (!this.id) {
if (!this.cal_id) {
alert("Empty id")
return
}
@@ -95,7 +94,7 @@ export class CreateCalendarForm extends LitElement {
alert("No calendar components selected")
return
}
await this.client.createDirectory(`/principal/${this.user}/${this.id}`, {
await this.client.createDirectory(`/principal/${this.user}/${this.cal_id}`, {
data: `
<mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/">
<set>

View File

@@ -1,7 +1,7 @@
{
"module": "nodenext",
"compilerOptions": {
"target": "es2024",
"moduleResolution": "bundler",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"lib": [

View File

@@ -1,10 +1,11 @@
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
// include: ["lit"]
},
build: {
minify: false,
modulePreload: {
polyfill: false
},
copyPublicDir: false,
lib: {
entry: 'lib/index.ts',

View File

@@ -1,50 +1,66 @@
import { i as c, x as u } from "./lit-CWlWuEHk.mjs";
import { n as o, t as h } from "./property-DYFkTqgI.mjs";
import { e as d, n as m } from "./ref-nf9JiOyl.mjs";
import { a as b } from "./webdav-Bz4I5vNH.mjs";
var y = Object.defineProperty, f = Object.getOwnPropertyDescriptor, r = (t, a, n, s) => {
for (var e = s > 1 ? void 0 : s ? f(a, n) : a, l = t.length - 1, p; l >= 0; l--)
(p = t[l]) && (e = (s ? p(a, n, e) : p(e)) || e);
return s && e && y(a, n, e), e;
import { i, x } from "./lit-z6_uA4GX.mjs";
import { n as n$1, t } from "./property-D0NJdseG.mjs";
import { e, n } from "./ref-CPp9J0V5.mjs";
import { a as an } from "./webdav-D0R7xCzX.mjs";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
if (decorator = decorators[i2])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
let i = class extends c {
let CreateAddressbookForm = class extends i {
constructor() {
super(), this.client = b("/carddav"), this.user = "", this.id = "", this.displayname = "", this.description = "", this.dialog = d(), this.form = d();
super();
this.client = an("/carddav");
this.user = "";
this.addr_id = "";
this.displayname = "";
this.description = "";
this.dialog = e();
this.form = e();
}
createRenderRoot() {
return this;
}
render() {
return u`
return x`
<button @click=${() => this.dialog.value.showModal()}>Create addressbook</button>
<dialog ${m(this.dialog)}>
<dialog ${n(this.dialog)}>
<h3>Create addressbook</h3>
<form @submit=${this.submit} ${m(this.form)}>
<form @submit=${this.submit} ${n(this.form)}>
<label>
id
<input type="text" name="id" @change=${(t) => this.id = t.target.value} />
<input type="text" name="id" @change=${(e2) => this.addr_id = e2.target.value} />
</label>
<br>
<label>
Displayname
<input type="text" name="displayname" value=${this.displayname} @change=${(t) => this.displayname = t.target.value} />
<input type="text" name="displayname" value=${this.displayname} @change=${(e2) => this.displayname = e2.target.value} />
</label>
<br>
<label>
Description
<input type="text" name="description" @change=${(t) => this.description = t.target.value} />
<input type="text" name="description" @change=${(e2) => this.description = e2.target.value} />
</label>
<br>
<button type="submit">Create</button>
<button type="submit" @click=${(t) => {
t.preventDefault(), this.dialog.value.close(), this.form.value.reset();
<button type="submit" @click=${(event) => {
event.preventDefault();
this.dialog.value.close();
this.form.value.reset();
}}> Cancel </button>
</form>
</dialog>
`;
}
async submit(t) {
if (console.log(this.displayname), t.preventDefault(), !this.id) {
async submit(e2) {
console.log(this.displayname);
e2.preventDefault();
if (!this.addr_id) {
alert("Empty id");
return;
}
@@ -52,7 +68,7 @@ let i = class extends c {
alert("Empty displayname");
return;
}
return await this.client.createDirectory(`/principal/${this.user}/${this.id}`, {
await this.client.createDirectory(`/principal/${this.user}/${this.addr_id}`, {
data: `
<mkcol xmlns="DAV:" xmlns:CARD="urn:ietf:params:xml:ns:carddav">
<set>
@@ -63,24 +79,26 @@ let i = class extends c {
</set>
</mkcol>
`
}), window.location.reload(), null;
});
window.location.reload();
return null;
}
};
r([
o()
], i.prototype, "user", 2);
r([
o()
], i.prototype, "id", 2);
r([
o()
], i.prototype, "displayname", 2);
r([
o()
], i.prototype, "description", 2);
i = r([
h("create-addressbook-form")
], i);
__decorateClass([
n$1()
], CreateAddressbookForm.prototype, "user", 2);
__decorateClass([
n$1()
], CreateAddressbookForm.prototype, "addr_id", 2);
__decorateClass([
n$1()
], CreateAddressbookForm.prototype, "displayname", 2);
__decorateClass([
n$1()
], CreateAddressbookForm.prototype, "description", 2);
CreateAddressbookForm = __decorateClass([
t("create-addressbook-form")
], CreateAddressbookForm);
export {
i as CreateAddressbookForm
CreateAddressbookForm
};

View File

@@ -1,67 +1,86 @@
import { i as u, x as c } from "./lit-CWlWuEHk.mjs";
import { n as o, t as h } from "./property-DYFkTqgI.mjs";
import { e as m, n as d } from "./ref-nf9JiOyl.mjs";
import { a as b } from "./webdav-Bz4I5vNH.mjs";
var y = Object.defineProperty, $ = Object.getOwnPropertyDescriptor, a = (t, e, n, s) => {
for (var i = s > 1 ? void 0 : s ? $(e, n) : e, l = t.length - 1, p; l >= 0; l--)
(p = t[l]) && (i = (s ? p(e, n, i) : p(i)) || i);
return s && i && y(e, n, i), i;
import { i, x } from "./lit-z6_uA4GX.mjs";
import { n as n$1, t } from "./property-D0NJdseG.mjs";
import { e, n } from "./ref-CPp9J0V5.mjs";
import { a as an } from "./webdav-D0R7xCzX.mjs";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
if (decorator = decorators[i2])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
let r = class extends u {
let CreateCalendarForm = class extends i {
constructor() {
super(), this.client = b("/caldav"), this.user = "", this.id = "", this.displayname = "", this.description = "", this.color = "", this.subscriptionUrl = "", this.components = /* @__PURE__ */ new Set(), this.dialog = m(), this.form = m();
super();
this.client = an("/caldav");
this.user = "";
this.cal_id = "";
this.displayname = "";
this.description = "";
this.color = "";
this.subscriptionUrl = "";
this.components = /* @__PURE__ */ new Set();
this.dialog = e();
this.form = e();
}
createRenderRoot() {
return this;
}
render() {
return c`
return x`
<button @click=${() => this.dialog.value.showModal()}>Create calendar</button>
<dialog ${d(this.dialog)}>
<dialog ${n(this.dialog)}>
<h3>Create calendar</h3>
<form @submit=${this.submit} ${d(this.form)}>
<form @submit=${this.submit} ${n(this.form)}>
<label>
id
<input type="text" name="id" @change=${(t) => this.id = t.target.value} />
<input type="text" name="id" @change=${(e2) => this.cal_id = e2.target.value} />
</label>
<br>
<label>
Displayname
<input type="text" name="displayname" value=${this.displayname} @change=${(t) => this.displayname = t.target.value} />
<input type="text" name="displayname" value=${this.displayname} @change=${(e2) => this.displayname = e2.target.value} />
</label>
<br>
<label>
Description
<input type="text" name="description" @change=${(t) => this.description = t.target.value} />
<input type="text" name="description" @change=${(e2) => this.description = e2.target.value} />
</label>
<br>
<label>
Color
<input type="color" name="color" @change=${(t) => this.color = t.target.value} />
<input type="color" name="color" @change=${(e2) => this.color = e2.target.value} />
</label>
<br>
<label>
Subscription URL
<input type="text" name="subscription_url" @change=${(t) => this.subscriptionUrl = t.target.value} />
<input type="text" name="subscription_url" @change=${(e2) => this.subscriptionUrl = e2.target.value} />
</label>
<br>
${["VEVENT", "VTODO", "VJOURNAL"].map((t) => c`
${["VEVENT", "VTODO", "VJOURNAL"].map((comp) => x`
<label>
Support ${t}
<input type="checkbox" value=${t} @change=${(e) => e.target.checked ? this.components.add(e.target.value) : this.components.delete(e.target.value)} />
Support ${comp}
<input type="checkbox" value=${comp} @change=${(e2) => e2.target.checked ? this.components.add(e2.target.value) : this.components.delete(e2.target.value)} />
</label>
`)}
<br>
<button type="submit">Create</button>
<button type="submit" @click=${(t) => {
t.preventDefault(), this.dialog.value.close(), this.form.value.reset();
<button type="submit" @click=${(event) => {
event.preventDefault();
this.dialog.value.close();
this.form.value.reset();
}}> Cancel </button>
</form>
</dialog>
`;
}
async submit(t) {
if (console.log(this.displayname), t.preventDefault(), !this.id) {
async submit(e2) {
console.log(this.displayname);
e2.preventDefault();
if (!this.cal_id) {
alert("Empty id");
return;
}
@@ -73,7 +92,7 @@ let r = class extends u {
alert("No calendar components selected");
return;
}
return await this.client.createDirectory(`/principal/${this.user}/${this.id}`, {
await this.client.createDirectory(`/principal/${this.user}/${this.cal_id}`, {
data: `
<mkcol xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/" xmlns:ICAL="http://apple.com/ns/ical/">
<set>
@@ -83,40 +102,41 @@ let r = class extends u {
${this.color ? `<ICAL:calendar-color>${this.color}</ICAL:calendar-color>` : ""}
${this.subscriptionUrl ? `<CS:source><href>${this.subscriptionUrl}</href></CS:source>` : ""}
<CAL:supported-calendar-component-set>
${Array.from(this.components.keys()).map((e) => `<CAL:comp name="${e}" />`).join(`
`)}
${Array.from(this.components.keys()).map((comp) => `<CAL:comp name="${comp}" />`).join("\n")}
</CAL:supported-calendar-component-set>
</prop>
</set>
</mkcol>
`
}), window.location.reload(), null;
});
window.location.reload();
return null;
}
};
a([
o()
], r.prototype, "user", 2);
a([
o()
], r.prototype, "id", 2);
a([
o()
], r.prototype, "displayname", 2);
a([
o()
], r.prototype, "description", 2);
a([
o()
], r.prototype, "color", 2);
a([
o()
], r.prototype, "subscriptionUrl", 2);
a([
o()
], r.prototype, "components", 2);
r = a([
h("create-calendar-form")
], r);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "user", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "cal_id", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "displayname", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "description", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "color", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "subscriptionUrl", 2);
__decorateClass([
n$1()
], CreateCalendarForm.prototype, "components", 2);
CreateCalendarForm = __decorateClass([
t("create-calendar-form")
], CreateCalendarForm);
export {
r as CreateCalendarForm
CreateCalendarForm
};

View File

@@ -1,46 +1,55 @@
import { i as c, x as p } from "./lit-CWlWuEHk.mjs";
import { n as h, t as u } from "./property-DYFkTqgI.mjs";
var f = Object.defineProperty, d = Object.getOwnPropertyDescriptor, i = (r, t, n, o) => {
for (var e = o > 1 ? void 0 : o ? d(t, n) : t, l = r.length - 1, a; l >= 0; l--)
(a = r[l]) && (e = (o ? a(t, n, e) : a(e)) || e);
return o && e && f(t, n, e), e;
import { i, x } from "./lit-z6_uA4GX.mjs";
import { n, t } from "./property-D0NJdseG.mjs";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
if (decorator = decorators[i2])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
let s = class extends c {
let DeleteButton = class extends i {
constructor() {
super(), this.trash = !1;
super();
this.trash = false;
}
createRenderRoot() {
return this;
}
render() {
let r = this.trash ? "Move to trash" : "Delete";
return p`<button class="delete" @click=${(t) => this._onClick(t)}>${r}</button>`;
let text = this.trash ? "Move to trash" : "Delete";
return x`<button class="delete" @click=${(e) => this._onClick(e)}>${text}</button>`;
}
async _onClick(r) {
if (r.preventDefault(), !this.trash && !confirm("Do you want to delete this collection permanently?"))
async _onClick(event) {
event.preventDefault();
if (!this.trash && !confirm("Do you want to delete this collection permanently?")) {
return;
let t = await fetch(this.href, {
}
let response = await fetch(this.href, {
method: "DELETE",
headers: {
"X-No-Trashbin": this.trash ? "0" : "1"
}
});
if (t.status < 200 || t.status >= 300) {
alert("An error occured, look into the console"), console.error(t);
if (response.status < 200 || response.status >= 300) {
alert("An error occured, look into the console");
console.error(response);
return;
}
window.location.reload();
}
};
i([
h({ type: Boolean })
], s.prototype, "trash", 2);
i([
h()
], s.prototype, "href", 2);
s = i([
u("delete-button")
], s);
__decorateClass([
n({ type: Boolean })
], DeleteButton.prototype, "trash", 2);
__decorateClass([
n()
], DeleteButton.prototype, "href", 2);
DeleteButton = __decorateClass([
t("delete-button")
], DeleteButton);
export {
s as DeleteButton
DeleteButton
};

View File

@@ -1,551 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const M = globalThis, B = M.ShadowRoot && (M.ShadyCSS === void 0 || M.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, tt = Symbol(), W = /* @__PURE__ */ new WeakMap();
let ot = class {
constructor(t, e, s) {
if (this._$cssResult$ = !0, s !== tt) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
this.cssText = t, this.t = e;
}
get styleSheet() {
let t = this.o;
const e = this.t;
if (B && t === void 0) {
const s = e !== void 0 && e.length === 1;
s && (t = W.get(e)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), s && W.set(e, t));
}
return t;
}
toString() {
return this.cssText;
}
};
const ht = (r) => new ot(typeof r == "string" ? r : r + "", void 0, tt), at = (r, t) => {
if (B) r.adoptedStyleSheets = t.map((e) => e instanceof CSSStyleSheet ? e : e.styleSheet);
else for (const e of t) {
const s = document.createElement("style"), i = M.litNonce;
i !== void 0 && s.setAttribute("nonce", i), s.textContent = e.cssText, r.appendChild(s);
}
}, V = B ? (r) => r : (r) => r instanceof CSSStyleSheet ? ((t) => {
let e = "";
for (const s of t.cssRules) e += s.cssText;
return ht(e);
})(r) : r;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const { is: lt, defineProperty: ct, getOwnPropertyDescriptor: dt, getOwnPropertyNames: pt, getOwnPropertySymbols: ut, getPrototypeOf: $t } = Object, f = globalThis, q = f.trustedTypes, _t = q ? q.emptyScript : "", k = f.reactiveElementPolyfillSupport, w = (r, t) => r, j = { toAttribute(r, t) {
switch (t) {
case Boolean:
r = r ? _t : null;
break;
case Object:
case Array:
r = r == null ? r : JSON.stringify(r);
}
return r;
}, fromAttribute(r, t) {
let e = r;
switch (t) {
case Boolean:
e = r !== null;
break;
case Number:
e = r === null ? null : Number(r);
break;
case Object:
case Array:
try {
e = JSON.parse(r);
} catch {
e = null;
}
}
return e;
} }, et = (r, t) => !lt(r, t), J = { attribute: !0, type: String, converter: j, reflect: !1, useDefault: !1, hasChanged: et };
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), f.litPropertyMetadata ?? (f.litPropertyMetadata = /* @__PURE__ */ new WeakMap());
let v = class extends HTMLElement {
static addInitializer(t) {
this._$Ei(), (this.l ?? (this.l = [])).push(t);
}
static get observedAttributes() {
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
}
static createProperty(t, e = J) {
if (e.state && (e.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(t) && ((e = Object.create(e)).wrapped = !0), this.elementProperties.set(t, e), !e.noAccessor) {
const s = Symbol(), i = this.getPropertyDescriptor(t, s, e);
i !== void 0 && ct(this.prototype, t, i);
}
}
static getPropertyDescriptor(t, e, s) {
const { get: i, set: n } = dt(this.prototype, t) ?? { get() {
return this[e];
}, set(o) {
this[e] = o;
} };
return { get: i, set(o) {
const a = i == null ? void 0 : i.call(this);
n == null || n.call(this, o), this.requestUpdate(t, a, s);
}, configurable: !0, enumerable: !0 };
}
static getPropertyOptions(t) {
return this.elementProperties.get(t) ?? J;
}
static _$Ei() {
if (this.hasOwnProperty(w("elementProperties"))) return;
const t = $t(this);
t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties);
}
static finalize() {
if (this.hasOwnProperty(w("finalized"))) return;
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(w("properties"))) {
const e = this.properties, s = [...pt(e), ...ut(e)];
for (const i of s) this.createProperty(i, e[i]);
}
const t = this[Symbol.metadata];
if (t !== null) {
const e = litPropertyMetadata.get(t);
if (e !== void 0) for (const [s, i] of e) this.elementProperties.set(s, i);
}
this._$Eh = /* @__PURE__ */ new Map();
for (const [e, s] of this.elementProperties) {
const i = this._$Eu(e, s);
i !== void 0 && this._$Eh.set(i, e);
}
this.elementStyles = this.finalizeStyles(this.styles);
}
static finalizeStyles(t) {
const e = [];
if (Array.isArray(t)) {
const s = new Set(t.flat(1 / 0).reverse());
for (const i of s) e.unshift(V(i));
} else t !== void 0 && e.push(V(t));
return e;
}
static _$Eu(t, e) {
const s = e.attribute;
return s === !1 ? void 0 : typeof s == "string" ? s : typeof t == "string" ? t.toLowerCase() : void 0;
}
constructor() {
super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev();
}
_$Ev() {
var t;
this._$ES = new Promise((e) => this.enableUpdating = e), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (t = this.constructor.l) == null || t.forEach((e) => e(this));
}
addController(t) {
var e;
(this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(t), this.renderRoot !== void 0 && this.isConnected && ((e = t.hostConnected) == null || e.call(t));
}
removeController(t) {
var e;
(e = this._$EO) == null || e.delete(t);
}
_$E_() {
const t = /* @__PURE__ */ new Map(), e = this.constructor.elementProperties;
for (const s of e.keys()) this.hasOwnProperty(s) && (t.set(s, this[s]), delete this[s]);
t.size > 0 && (this._$Ep = t);
}
createRenderRoot() {
const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
return at(t, this.constructor.elementStyles), t;
}
connectedCallback() {
var t;
this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (t = this._$EO) == null || t.forEach((e) => {
var s;
return (s = e.hostConnected) == null ? void 0 : s.call(e);
});
}
enableUpdating(t) {
}
disconnectedCallback() {
var t;
(t = this._$EO) == null || t.forEach((e) => {
var s;
return (s = e.hostDisconnected) == null ? void 0 : s.call(e);
});
}
attributeChangedCallback(t, e, s) {
this._$AK(t, s);
}
_$ET(t, e) {
var n;
const s = this.constructor.elementProperties.get(t), i = this.constructor._$Eu(t, s);
if (i !== void 0 && s.reflect === !0) {
const o = (((n = s.converter) == null ? void 0 : n.toAttribute) !== void 0 ? s.converter : j).toAttribute(e, s.type);
this._$Em = t, o == null ? this.removeAttribute(i) : this.setAttribute(i, o), this._$Em = null;
}
}
_$AK(t, e) {
var n, o;
const s = this.constructor, i = s._$Eh.get(t);
if (i !== void 0 && this._$Em !== i) {
const a = s.getPropertyOptions(i), h = typeof a.converter == "function" ? { fromAttribute: a.converter } : ((n = a.converter) == null ? void 0 : n.fromAttribute) !== void 0 ? a.converter : j;
this._$Em = i, this[i] = h.fromAttribute(e, a.type) ?? ((o = this._$Ej) == null ? void 0 : o.get(i)) ?? null, this._$Em = null;
}
}
requestUpdate(t, e, s) {
var i;
if (t !== void 0) {
const n = this.constructor, o = this[t];
if (s ?? (s = n.getPropertyOptions(t)), !((s.hasChanged ?? et)(o, e) || s.useDefault && s.reflect && o === ((i = this._$Ej) == null ? void 0 : i.get(t)) && !this.hasAttribute(n._$Eu(t, s)))) return;
this.C(t, e, s);
}
this.isUpdatePending === !1 && (this._$ES = this._$EP());
}
C(t, e, { useDefault: s, reflect: i, wrapped: n }, o) {
s && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(t) && (this._$Ej.set(t, o ?? e ?? this[t]), n !== !0 || o !== void 0) || (this._$AL.has(t) || (this.hasUpdated || s || (e = void 0), this._$AL.set(t, e)), i === !0 && this._$Em !== t && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(t));
}
async _$EP() {
this.isUpdatePending = !0;
try {
await this._$ES;
} catch (e) {
Promise.reject(e);
}
const t = this.scheduleUpdate();
return t != null && await t, !this.isUpdatePending;
}
scheduleUpdate() {
return this.performUpdate();
}
performUpdate() {
var s;
if (!this.isUpdatePending) return;
if (!this.hasUpdated) {
if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) {
for (const [n, o] of this._$Ep) this[n] = o;
this._$Ep = void 0;
}
const i = this.constructor.elementProperties;
if (i.size > 0) for (const [n, o] of i) {
const { wrapped: a } = o, h = this[n];
a !== !0 || this._$AL.has(n) || h === void 0 || this.C(n, void 0, o, h);
}
}
let t = !1;
const e = this._$AL;
try {
t = this.shouldUpdate(e), t ? (this.willUpdate(e), (s = this._$EO) == null || s.forEach((i) => {
var n;
return (n = i.hostUpdate) == null ? void 0 : n.call(i);
}), this.update(e)) : this._$EM();
} catch (i) {
throw t = !1, this._$EM(), i;
}
t && this._$AE(e);
}
willUpdate(t) {
}
_$AE(t) {
var e;
(e = this._$EO) == null || e.forEach((s) => {
var i;
return (i = s.hostUpdated) == null ? void 0 : i.call(s);
}), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(t)), this.updated(t);
}
_$EM() {
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1;
}
get updateComplete() {
return this.getUpdateComplete();
}
getUpdateComplete() {
return this._$ES;
}
shouldUpdate(t) {
return !0;
}
update(t) {
this._$Eq && (this._$Eq = this._$Eq.forEach((e) => this._$ET(e, this[e]))), this._$EM();
}
updated(t) {
}
firstUpdated(t) {
}
};
v.elementStyles = [], v.shadowRootOptions = { mode: "open" }, v[w("elementProperties")] = /* @__PURE__ */ new Map(), v[w("finalized")] = /* @__PURE__ */ new Map(), k == null || k({ ReactiveElement: v }), (f.reactiveElementVersions ?? (f.reactiveElementVersions = [])).push("2.1.0");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const C = globalThis, N = C.trustedTypes, K = N ? N.createPolicy("lit-html", { createHTML: (r) => r }) : void 0, st = "$lit$", _ = `lit$${Math.random().toFixed(9).slice(2)}$`, it = "?" + _, ft = `<${it}>`, g = document, P = () => g.createComment(""), x = (r) => r === null || typeof r != "object" && typeof r != "function", I = Array.isArray, At = (r) => I(r) || typeof (r == null ? void 0 : r[Symbol.iterator]) == "function", D = `[
\f\r]`, b = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, Z = /-->/g, F = />/g, A = RegExp(`>|${D}(?:([^\\s"'>=/]+)(${D}*=${D}*(?:[^
\f\r"'\`<>=]|("|')|))|$)`, "g"), G = /'/g, Q = /"/g, rt = /^(?:script|style|textarea|title)$/i, mt = (r) => (t, ...e) => ({ _$litType$: r, strings: t, values: e }), xt = mt(1), E = Symbol.for("lit-noChange"), d = Symbol.for("lit-nothing"), X = /* @__PURE__ */ new WeakMap(), m = g.createTreeWalker(g, 129);
function nt(r, t) {
if (!I(r) || !r.hasOwnProperty("raw")) throw Error("invalid template strings array");
return K !== void 0 ? K.createHTML(t) : t;
}
const yt = (r, t) => {
const e = r.length - 1, s = [];
let i, n = t === 2 ? "<svg>" : t === 3 ? "<math>" : "", o = b;
for (let a = 0; a < e; a++) {
const h = r[a];
let c, p, l = -1, u = 0;
for (; u < h.length && (o.lastIndex = u, p = o.exec(h), p !== null); ) u = o.lastIndex, o === b ? p[1] === "!--" ? o = Z : p[1] !== void 0 ? o = F : p[2] !== void 0 ? (rt.test(p[2]) && (i = RegExp("</" + p[2], "g")), o = A) : p[3] !== void 0 && (o = A) : o === A ? p[0] === ">" ? (o = i ?? b, l = -1) : p[1] === void 0 ? l = -2 : (l = o.lastIndex - p[2].length, c = p[1], o = p[3] === void 0 ? A : p[3] === '"' ? Q : G) : o === Q || o === G ? o = A : o === Z || o === F ? o = b : (o = A, i = void 0);
const $ = o === A && r[a + 1].startsWith("/>") ? " " : "";
n += o === b ? h + ft : l >= 0 ? (s.push(c), h.slice(0, l) + st + h.slice(l) + _ + $) : h + _ + (l === -2 ? a : $);
}
return [nt(r, n + (r[e] || "<?>") + (t === 2 ? "</svg>" : t === 3 ? "</math>" : "")), s];
};
class U {
constructor({ strings: t, _$litType$: e }, s) {
let i;
this.parts = [];
let n = 0, o = 0;
const a = t.length - 1, h = this.parts, [c, p] = yt(t, e);
if (this.el = U.createElement(c, s), m.currentNode = this.el.content, e === 2 || e === 3) {
const l = this.el.content.firstChild;
l.replaceWith(...l.childNodes);
}
for (; (i = m.nextNode()) !== null && h.length < a; ) {
if (i.nodeType === 1) {
if (i.hasAttributes()) for (const l of i.getAttributeNames()) if (l.endsWith(st)) {
const u = p[o++], $ = i.getAttribute(l).split(_), H = /([.?@])?(.*)/.exec(u);
h.push({ type: 1, index: n, name: H[2], strings: $, ctor: H[1] === "." ? vt : H[1] === "?" ? Et : H[1] === "@" ? St : R }), i.removeAttribute(l);
} else l.startsWith(_) && (h.push({ type: 6, index: n }), i.removeAttribute(l));
if (rt.test(i.tagName)) {
const l = i.textContent.split(_), u = l.length - 1;
if (u > 0) {
i.textContent = N ? N.emptyScript : "";
for (let $ = 0; $ < u; $++) i.append(l[$], P()), m.nextNode(), h.push({ type: 2, index: ++n });
i.append(l[u], P());
}
}
} else if (i.nodeType === 8) if (i.data === it) h.push({ type: 2, index: n });
else {
let l = -1;
for (; (l = i.data.indexOf(_, l + 1)) !== -1; ) h.push({ type: 7, index: n }), l += _.length - 1;
}
n++;
}
}
static createElement(t, e) {
const s = g.createElement("template");
return s.innerHTML = t, s;
}
}
function S(r, t, e = r, s) {
var o, a;
if (t === E) return t;
let i = s !== void 0 ? (o = e._$Co) == null ? void 0 : o[s] : e._$Cl;
const n = x(t) ? void 0 : t._$litDirective$;
return (i == null ? void 0 : i.constructor) !== n && ((a = i == null ? void 0 : i._$AO) == null || a.call(i, !1), n === void 0 ? i = void 0 : (i = new n(r), i._$AT(r, e, s)), s !== void 0 ? (e._$Co ?? (e._$Co = []))[s] = i : e._$Cl = i), i !== void 0 && (t = S(r, i._$AS(r, t.values), i, s)), t;
}
class gt {
constructor(t, e) {
this._$AV = [], this._$AN = void 0, this._$AD = t, this._$AM = e;
}
get parentNode() {
return this._$AM.parentNode;
}
get _$AU() {
return this._$AM._$AU;
}
u(t) {
const { el: { content: e }, parts: s } = this._$AD, i = ((t == null ? void 0 : t.creationScope) ?? g).importNode(e, !0);
m.currentNode = i;
let n = m.nextNode(), o = 0, a = 0, h = s[0];
for (; h !== void 0; ) {
if (o === h.index) {
let c;
h.type === 2 ? c = new O(n, n.nextSibling, this, t) : h.type === 1 ? c = new h.ctor(n, h.name, h.strings, this, t) : h.type === 6 && (c = new bt(n, this, t)), this._$AV.push(c), h = s[++a];
}
o !== (h == null ? void 0 : h.index) && (n = m.nextNode(), o++);
}
return m.currentNode = g, i;
}
p(t) {
let e = 0;
for (const s of this._$AV) s !== void 0 && (s.strings !== void 0 ? (s._$AI(t, s, e), e += s.strings.length - 2) : s._$AI(t[e])), e++;
}
}
class O {
get _$AU() {
var t;
return ((t = this._$AM) == null ? void 0 : t._$AU) ?? this._$Cv;
}
constructor(t, e, s, i) {
this.type = 2, this._$AH = d, this._$AN = void 0, this._$AA = t, this._$AB = e, this._$AM = s, this.options = i, this._$Cv = (i == null ? void 0 : i.isConnected) ?? !0;
}
get parentNode() {
let t = this._$AA.parentNode;
const e = this._$AM;
return e !== void 0 && (t == null ? void 0 : t.nodeType) === 11 && (t = e.parentNode), t;
}
get startNode() {
return this._$AA;
}
get endNode() {
return this._$AB;
}
_$AI(t, e = this) {
t = S(this, t, e), x(t) ? t === d || t == null || t === "" ? (this._$AH !== d && this._$AR(), this._$AH = d) : t !== this._$AH && t !== E && this._(t) : t._$litType$ !== void 0 ? this.$(t) : t.nodeType !== void 0 ? this.T(t) : At(t) ? this.k(t) : this._(t);
}
O(t) {
return this._$AA.parentNode.insertBefore(t, this._$AB);
}
T(t) {
this._$AH !== t && (this._$AR(), this._$AH = this.O(t));
}
_(t) {
this._$AH !== d && x(this._$AH) ? this._$AA.nextSibling.data = t : this.T(g.createTextNode(t)), this._$AH = t;
}
$(t) {
var n;
const { values: e, _$litType$: s } = t, i = typeof s == "number" ? this._$AC(t) : (s.el === void 0 && (s.el = U.createElement(nt(s.h, s.h[0]), this.options)), s);
if (((n = this._$AH) == null ? void 0 : n._$AD) === i) this._$AH.p(e);
else {
const o = new gt(i, this), a = o.u(this.options);
o.p(e), this.T(a), this._$AH = o;
}
}
_$AC(t) {
let e = X.get(t.strings);
return e === void 0 && X.set(t.strings, e = new U(t)), e;
}
k(t) {
I(this._$AH) || (this._$AH = [], this._$AR());
const e = this._$AH;
let s, i = 0;
for (const n of t) i === e.length ? e.push(s = new O(this.O(P()), this.O(P()), this, this.options)) : s = e[i], s._$AI(n), i++;
i < e.length && (this._$AR(s && s._$AB.nextSibling, i), e.length = i);
}
_$AR(t = this._$AA.nextSibling, e) {
var s;
for ((s = this._$AP) == null ? void 0 : s.call(this, !1, !0, e); t && t !== this._$AB; ) {
const i = t.nextSibling;
t.remove(), t = i;
}
}
setConnected(t) {
var e;
this._$AM === void 0 && (this._$Cv = t, (e = this._$AP) == null || e.call(this, t));
}
}
class R {
get tagName() {
return this.element.tagName;
}
get _$AU() {
return this._$AM._$AU;
}
constructor(t, e, s, i, n) {
this.type = 1, this._$AH = d, this._$AN = void 0, this.element = t, this.name = e, this._$AM = i, this.options = n, s.length > 2 || s[0] !== "" || s[1] !== "" ? (this._$AH = Array(s.length - 1).fill(new String()), this.strings = s) : this._$AH = d;
}
_$AI(t, e = this, s, i) {
const n = this.strings;
let o = !1;
if (n === void 0) t = S(this, t, e, 0), o = !x(t) || t !== this._$AH && t !== E, o && (this._$AH = t);
else {
const a = t;
let h, c;
for (t = n[0], h = 0; h < n.length - 1; h++) c = S(this, a[s + h], e, h), c === E && (c = this._$AH[h]), o || (o = !x(c) || c !== this._$AH[h]), c === d ? t = d : t !== d && (t += (c ?? "") + n[h + 1]), this._$AH[h] = c;
}
o && !i && this.j(t);
}
j(t) {
t === d ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t ?? "");
}
}
class vt extends R {
constructor() {
super(...arguments), this.type = 3;
}
j(t) {
this.element[this.name] = t === d ? void 0 : t;
}
}
class Et extends R {
constructor() {
super(...arguments), this.type = 4;
}
j(t) {
this.element.toggleAttribute(this.name, !!t && t !== d);
}
}
class St extends R {
constructor(t, e, s, i, n) {
super(t, e, s, i, n), this.type = 5;
}
_$AI(t, e = this) {
if ((t = S(this, t, e, 0) ?? d) === E) return;
const s = this._$AH, i = t === d && s !== d || t.capture !== s.capture || t.once !== s.once || t.passive !== s.passive, n = t !== d && (s === d || i);
i && this.element.removeEventListener(this.name, this, s), n && this.element.addEventListener(this.name, this, t), this._$AH = t;
}
handleEvent(t) {
var e;
typeof this._$AH == "function" ? this._$AH.call(((e = this.options) == null ? void 0 : e.host) ?? this.element, t) : this._$AH.handleEvent(t);
}
}
class bt {
constructor(t, e, s) {
this.element = t, this.type = 6, this._$AN = void 0, this._$AM = e, this.options = s;
}
get _$AU() {
return this._$AM._$AU;
}
_$AI(t) {
S(this, t);
}
}
const L = C.litHtmlPolyfillSupport;
L == null || L(U, O), (C.litHtmlVersions ?? (C.litHtmlVersions = [])).push("3.3.0");
const wt = (r, t, e) => {
const s = (e == null ? void 0 : e.renderBefore) ?? t;
let i = s._$litPart$;
if (i === void 0) {
const n = (e == null ? void 0 : e.renderBefore) ?? null;
s._$litPart$ = i = new O(t.insertBefore(P(), n), n, void 0, e ?? {});
}
return i._$AI(r), i;
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const y = globalThis;
class T extends v {
constructor() {
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
}
createRenderRoot() {
var e;
const t = super.createRenderRoot();
return (e = this.renderOptions).renderBefore ?? (e.renderBefore = t.firstChild), t;
}
update(t) {
const e = this.render();
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t), this._$Do = wt(e, this.renderRoot, this.renderOptions);
}
connectedCallback() {
var t;
super.connectedCallback(), (t = this._$Do) == null || t.setConnected(!0);
}
disconnectedCallback() {
var t;
super.disconnectedCallback(), (t = this._$Do) == null || t.setConnected(!1);
}
render() {
return E;
}
}
var Y;
T._$litElement$ = !0, T.finalized = !0, (Y = y.litElementHydrateSupport) == null || Y.call(y, { LitElement: T });
const z = y.litElementPolyfillSupport;
z == null || z({ LitElement: T });
(y.litElementVersions ?? (y.litElementVersions = [])).push("4.2.0");
export {
d as E,
et as f,
T as i,
j as u,
xt as x
};

View File

@@ -0,0 +1,550 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
var _a;
const t$1 = globalThis, e$2 = t$1.ShadowRoot && (void 0 === t$1.ShadyCSS || t$1.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$2 = Symbol(), o$3 = /* @__PURE__ */ new WeakMap();
let n$2 = class n {
constructor(t2, e2, o2) {
if (this._$cssResult$ = true, o2 !== s$2) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
this.cssText = t2, this.t = e2;
}
get styleSheet() {
let t2 = this.o;
const s2 = this.t;
if (e$2 && void 0 === t2) {
const e2 = void 0 !== s2 && 1 === s2.length;
e2 && (t2 = o$3.get(s2)), void 0 === t2 && ((this.o = t2 = new CSSStyleSheet()).replaceSync(this.cssText), e2 && o$3.set(s2, t2));
}
return t2;
}
toString() {
return this.cssText;
}
};
const r$2 = (t2) => new n$2("string" == typeof t2 ? t2 : t2 + "", void 0, s$2), S$1 = (s2, o2) => {
if (e$2) s2.adoptedStyleSheets = o2.map((t2) => t2 instanceof CSSStyleSheet ? t2 : t2.styleSheet);
else for (const e2 of o2) {
const o3 = document.createElement("style"), n3 = t$1.litNonce;
void 0 !== n3 && o3.setAttribute("nonce", n3), o3.textContent = e2.cssText, s2.appendChild(o3);
}
}, c$2 = e$2 ? (t2) => t2 : (t2) => t2 instanceof CSSStyleSheet ? ((t3) => {
let e2 = "";
for (const s2 of t3.cssRules) e2 += s2.cssText;
return r$2(e2);
})(t2) : t2;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const { is: i$2, defineProperty: e$1, getOwnPropertyDescriptor: h$1, getOwnPropertyNames: r$1, getOwnPropertySymbols: o$2, getPrototypeOf: n$1 } = Object, a$1 = globalThis, c$1 = a$1.trustedTypes, l$1 = c$1 ? c$1.emptyScript : "", p$1 = a$1.reactiveElementPolyfillSupport, d$1 = (t2, s2) => t2, u$1 = { toAttribute(t2, s2) {
switch (s2) {
case Boolean:
t2 = t2 ? l$1 : null;
break;
case Object:
case Array:
t2 = null == t2 ? t2 : JSON.stringify(t2);
}
return t2;
}, fromAttribute(t2, s2) {
let i2 = t2;
switch (s2) {
case Boolean:
i2 = null !== t2;
break;
case Number:
i2 = null === t2 ? null : Number(t2);
break;
case Object:
case Array:
try {
i2 = JSON.parse(t2);
} catch (t3) {
i2 = null;
}
}
return i2;
} }, f$1 = (t2, s2) => !i$2(t2, s2), b = { attribute: true, type: String, converter: u$1, reflect: false, useDefault: false, hasChanged: f$1 };
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), a$1.litPropertyMetadata ?? (a$1.litPropertyMetadata = /* @__PURE__ */ new WeakMap());
let y$1 = class y extends HTMLElement {
static addInitializer(t2) {
this._$Ei(), (this.l ?? (this.l = [])).push(t2);
}
static get observedAttributes() {
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
}
static createProperty(t2, s2 = b) {
if (s2.state && (s2.attribute = false), this._$Ei(), this.prototype.hasOwnProperty(t2) && ((s2 = Object.create(s2)).wrapped = true), this.elementProperties.set(t2, s2), !s2.noAccessor) {
const i2 = Symbol(), h2 = this.getPropertyDescriptor(t2, i2, s2);
void 0 !== h2 && e$1(this.prototype, t2, h2);
}
}
static getPropertyDescriptor(t2, s2, i2) {
const { get: e2, set: r2 } = h$1(this.prototype, t2) ?? { get() {
return this[s2];
}, set(t3) {
this[s2] = t3;
} };
return { get: e2, set(s3) {
const h2 = e2 == null ? void 0 : e2.call(this);
r2 == null ? void 0 : r2.call(this, s3), this.requestUpdate(t2, h2, i2);
}, configurable: true, enumerable: true };
}
static getPropertyOptions(t2) {
return this.elementProperties.get(t2) ?? b;
}
static _$Ei() {
if (this.hasOwnProperty(d$1("elementProperties"))) return;
const t2 = n$1(this);
t2.finalize(), void 0 !== t2.l && (this.l = [...t2.l]), this.elementProperties = new Map(t2.elementProperties);
}
static finalize() {
if (this.hasOwnProperty(d$1("finalized"))) return;
if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) {
const t3 = this.properties, s2 = [...r$1(t3), ...o$2(t3)];
for (const i2 of s2) this.createProperty(i2, t3[i2]);
}
const t2 = this[Symbol.metadata];
if (null !== t2) {
const s2 = litPropertyMetadata.get(t2);
if (void 0 !== s2) for (const [t3, i2] of s2) this.elementProperties.set(t3, i2);
}
this._$Eh = /* @__PURE__ */ new Map();
for (const [t3, s2] of this.elementProperties) {
const i2 = this._$Eu(t3, s2);
void 0 !== i2 && this._$Eh.set(i2, t3);
}
this.elementStyles = this.finalizeStyles(this.styles);
}
static finalizeStyles(s2) {
const i2 = [];
if (Array.isArray(s2)) {
const e2 = new Set(s2.flat(1 / 0).reverse());
for (const s3 of e2) i2.unshift(c$2(s3));
} else void 0 !== s2 && i2.push(c$2(s2));
return i2;
}
static _$Eu(t2, s2) {
const i2 = s2.attribute;
return false === i2 ? void 0 : "string" == typeof i2 ? i2 : "string" == typeof t2 ? t2.toLowerCase() : void 0;
}
constructor() {
super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev();
}
_$Ev() {
var _a2;
this._$ES = new Promise((t2) => this.enableUpdating = t2), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (_a2 = this.constructor.l) == null ? void 0 : _a2.forEach((t2) => t2(this));
}
addController(t2) {
var _a2;
(this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(t2), void 0 !== this.renderRoot && this.isConnected && ((_a2 = t2.hostConnected) == null ? void 0 : _a2.call(t2));
}
removeController(t2) {
var _a2;
(_a2 = this._$EO) == null ? void 0 : _a2.delete(t2);
}
_$E_() {
const t2 = /* @__PURE__ */ new Map(), s2 = this.constructor.elementProperties;
for (const i2 of s2.keys()) this.hasOwnProperty(i2) && (t2.set(i2, this[i2]), delete this[i2]);
t2.size > 0 && (this._$Ep = t2);
}
createRenderRoot() {
const t2 = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
return S$1(t2, this.constructor.elementStyles), t2;
}
connectedCallback() {
var _a2;
this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(true), (_a2 = this._$EO) == null ? void 0 : _a2.forEach((t2) => {
var _a3;
return (_a3 = t2.hostConnected) == null ? void 0 : _a3.call(t2);
});
}
enableUpdating(t2) {
}
disconnectedCallback() {
var _a2;
(_a2 = this._$EO) == null ? void 0 : _a2.forEach((t2) => {
var _a3;
return (_a3 = t2.hostDisconnected) == null ? void 0 : _a3.call(t2);
});
}
attributeChangedCallback(t2, s2, i2) {
this._$AK(t2, i2);
}
_$ET(t2, s2) {
var _a2;
const i2 = this.constructor.elementProperties.get(t2), e2 = this.constructor._$Eu(t2, i2);
if (void 0 !== e2 && true === i2.reflect) {
const h2 = (void 0 !== ((_a2 = i2.converter) == null ? void 0 : _a2.toAttribute) ? i2.converter : u$1).toAttribute(s2, i2.type);
this._$Em = t2, null == h2 ? this.removeAttribute(e2) : this.setAttribute(e2, h2), this._$Em = null;
}
}
_$AK(t2, s2) {
var _a2, _b;
const i2 = this.constructor, e2 = i2._$Eh.get(t2);
if (void 0 !== e2 && this._$Em !== e2) {
const t3 = i2.getPropertyOptions(e2), h2 = "function" == typeof t3.converter ? { fromAttribute: t3.converter } : void 0 !== ((_a2 = t3.converter) == null ? void 0 : _a2.fromAttribute) ? t3.converter : u$1;
this._$Em = e2, this[e2] = h2.fromAttribute(s2, t3.type) ?? ((_b = this._$Ej) == null ? void 0 : _b.get(e2)) ?? null, this._$Em = null;
}
}
requestUpdate(t2, s2, i2) {
var _a2;
if (void 0 !== t2) {
const e2 = this.constructor, h2 = this[t2];
if (i2 ?? (i2 = e2.getPropertyOptions(t2)), !((i2.hasChanged ?? f$1)(h2, s2) || i2.useDefault && i2.reflect && h2 === ((_a2 = this._$Ej) == null ? void 0 : _a2.get(t2)) && !this.hasAttribute(e2._$Eu(t2, i2)))) return;
this.C(t2, s2, i2);
}
false === this.isUpdatePending && (this._$ES = this._$EP());
}
C(t2, s2, { useDefault: i2, reflect: e2, wrapped: h2 }, r2) {
i2 && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(t2) && (this._$Ej.set(t2, r2 ?? s2 ?? this[t2]), true !== h2 || void 0 !== r2) || (this._$AL.has(t2) || (this.hasUpdated || i2 || (s2 = void 0), this._$AL.set(t2, s2)), true === e2 && this._$Em !== t2 && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(t2));
}
async _$EP() {
this.isUpdatePending = true;
try {
await this._$ES;
} catch (t3) {
Promise.reject(t3);
}
const t2 = this.scheduleUpdate();
return null != t2 && await t2, !this.isUpdatePending;
}
scheduleUpdate() {
return this.performUpdate();
}
performUpdate() {
var _a2;
if (!this.isUpdatePending) return;
if (!this.hasUpdated) {
if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) {
for (const [t4, s3] of this._$Ep) this[t4] = s3;
this._$Ep = void 0;
}
const t3 = this.constructor.elementProperties;
if (t3.size > 0) for (const [s3, i2] of t3) {
const { wrapped: t4 } = i2, e2 = this[s3];
true !== t4 || this._$AL.has(s3) || void 0 === e2 || this.C(s3, void 0, i2, e2);
}
}
let t2 = false;
const s2 = this._$AL;
try {
t2 = this.shouldUpdate(s2), t2 ? (this.willUpdate(s2), (_a2 = this._$EO) == null ? void 0 : _a2.forEach((t3) => {
var _a3;
return (_a3 = t3.hostUpdate) == null ? void 0 : _a3.call(t3);
}), this.update(s2)) : this._$EM();
} catch (s3) {
throw t2 = false, this._$EM(), s3;
}
t2 && this._$AE(s2);
}
willUpdate(t2) {
}
_$AE(t2) {
var _a2;
(_a2 = this._$EO) == null ? void 0 : _a2.forEach((t3) => {
var _a3;
return (_a3 = t3.hostUpdated) == null ? void 0 : _a3.call(t3);
}), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t2)), this.updated(t2);
}
_$EM() {
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = false;
}
get updateComplete() {
return this.getUpdateComplete();
}
getUpdateComplete() {
return this._$ES;
}
shouldUpdate(t2) {
return true;
}
update(t2) {
this._$Eq && (this._$Eq = this._$Eq.forEach((t3) => this._$ET(t3, this[t3]))), this._$EM();
}
updated(t2) {
}
firstUpdated(t2) {
}
};
y$1.elementStyles = [], y$1.shadowRootOptions = { mode: "open" }, y$1[d$1("elementProperties")] = /* @__PURE__ */ new Map(), y$1[d$1("finalized")] = /* @__PURE__ */ new Map(), p$1 == null ? void 0 : p$1({ ReactiveElement: y$1 }), (a$1.reactiveElementVersions ?? (a$1.reactiveElementVersions = [])).push("2.1.0");
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const t = globalThis, i$1 = t.trustedTypes, s$1 = i$1 ? i$1.createPolicy("lit-html", { createHTML: (t2) => t2 }) : void 0, e = "$lit$", h = `lit$${Math.random().toFixed(9).slice(2)}$`, o$1 = "?" + h, n2 = `<${o$1}>`, r = document, l = () => r.createComment(""), c = (t2) => null === t2 || "object" != typeof t2 && "function" != typeof t2, a = Array.isArray, u = (t2) => a(t2) || "function" == typeof (t2 == null ? void 0 : t2[Symbol.iterator]), d = "[ \n\f\r]", f = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, v = /-->/g, _ = />/g, m = RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^
\f\r"'\`<>=]|("|')|))|$)`, "g"), p = /'/g, g = /"/g, $ = /^(?:script|style|textarea|title)$/i, y2 = (t2) => (i2, ...s2) => ({ _$litType$: t2, strings: i2, values: s2 }), x = y2(1), T = Symbol.for("lit-noChange"), E = Symbol.for("lit-nothing"), A = /* @__PURE__ */ new WeakMap(), C = r.createTreeWalker(r, 129);
function P(t2, i2) {
if (!a(t2) || !t2.hasOwnProperty("raw")) throw Error("invalid template strings array");
return void 0 !== s$1 ? s$1.createHTML(i2) : i2;
}
const V = (t2, i2) => {
const s2 = t2.length - 1, o2 = [];
let r2, l2 = 2 === i2 ? "<svg>" : 3 === i2 ? "<math>" : "", c2 = f;
for (let i3 = 0; i3 < s2; i3++) {
const s3 = t2[i3];
let a2, u2, d2 = -1, y3 = 0;
for (; y3 < s3.length && (c2.lastIndex = y3, u2 = c2.exec(s3), null !== u2); ) y3 = c2.lastIndex, c2 === f ? "!--" === u2[1] ? c2 = v : void 0 !== u2[1] ? c2 = _ : void 0 !== u2[2] ? ($.test(u2[2]) && (r2 = RegExp("</" + u2[2], "g")), c2 = m) : void 0 !== u2[3] && (c2 = m) : c2 === m ? ">" === u2[0] ? (c2 = r2 ?? f, d2 = -1) : void 0 === u2[1] ? d2 = -2 : (d2 = c2.lastIndex - u2[2].length, a2 = u2[1], c2 = void 0 === u2[3] ? m : '"' === u2[3] ? g : p) : c2 === g || c2 === p ? c2 = m : c2 === v || c2 === _ ? c2 = f : (c2 = m, r2 = void 0);
const x2 = c2 === m && t2[i3 + 1].startsWith("/>") ? " " : "";
l2 += c2 === f ? s3 + n2 : d2 >= 0 ? (o2.push(a2), s3.slice(0, d2) + e + s3.slice(d2) + h + x2) : s3 + h + (-2 === d2 ? i3 : x2);
}
return [P(t2, l2 + (t2[s2] || "<?>") + (2 === i2 ? "</svg>" : 3 === i2 ? "</math>" : "")), o2];
};
class N {
constructor({ strings: t2, _$litType$: s2 }, n3) {
let r2;
this.parts = [];
let c2 = 0, a2 = 0;
const u2 = t2.length - 1, d2 = this.parts, [f2, v2] = V(t2, s2);
if (this.el = N.createElement(f2, n3), C.currentNode = this.el.content, 2 === s2 || 3 === s2) {
const t3 = this.el.content.firstChild;
t3.replaceWith(...t3.childNodes);
}
for (; null !== (r2 = C.nextNode()) && d2.length < u2; ) {
if (1 === r2.nodeType) {
if (r2.hasAttributes()) for (const t3 of r2.getAttributeNames()) if (t3.endsWith(e)) {
const i2 = v2[a2++], s3 = r2.getAttribute(t3).split(h), e2 = /([.?@])?(.*)/.exec(i2);
d2.push({ type: 1, index: c2, name: e2[2], strings: s3, ctor: "." === e2[1] ? H : "?" === e2[1] ? I : "@" === e2[1] ? L : k }), r2.removeAttribute(t3);
} else t3.startsWith(h) && (d2.push({ type: 6, index: c2 }), r2.removeAttribute(t3));
if ($.test(r2.tagName)) {
const t3 = r2.textContent.split(h), s3 = t3.length - 1;
if (s3 > 0) {
r2.textContent = i$1 ? i$1.emptyScript : "";
for (let i2 = 0; i2 < s3; i2++) r2.append(t3[i2], l()), C.nextNode(), d2.push({ type: 2, index: ++c2 });
r2.append(t3[s3], l());
}
}
} else if (8 === r2.nodeType) if (r2.data === o$1) d2.push({ type: 2, index: c2 });
else {
let t3 = -1;
for (; -1 !== (t3 = r2.data.indexOf(h, t3 + 1)); ) d2.push({ type: 7, index: c2 }), t3 += h.length - 1;
}
c2++;
}
}
static createElement(t2, i2) {
const s2 = r.createElement("template");
return s2.innerHTML = t2, s2;
}
}
function S(t2, i2, s2 = t2, e2) {
var _a2, _b;
if (i2 === T) return i2;
let h2 = void 0 !== e2 ? (_a2 = s2._$Co) == null ? void 0 : _a2[e2] : s2._$Cl;
const o2 = c(i2) ? void 0 : i2._$litDirective$;
return (h2 == null ? void 0 : h2.constructor) !== o2 && ((_b = h2 == null ? void 0 : h2._$AO) == null ? void 0 : _b.call(h2, false), void 0 === o2 ? h2 = void 0 : (h2 = new o2(t2), h2._$AT(t2, s2, e2)), void 0 !== e2 ? (s2._$Co ?? (s2._$Co = []))[e2] = h2 : s2._$Cl = h2), void 0 !== h2 && (i2 = S(t2, h2._$AS(t2, i2.values), h2, e2)), i2;
}
class M {
constructor(t2, i2) {
this._$AV = [], this._$AN = void 0, this._$AD = t2, this._$AM = i2;
}
get parentNode() {
return this._$AM.parentNode;
}
get _$AU() {
return this._$AM._$AU;
}
u(t2) {
const { el: { content: i2 }, parts: s2 } = this._$AD, e2 = ((t2 == null ? void 0 : t2.creationScope) ?? r).importNode(i2, true);
C.currentNode = e2;
let h2 = C.nextNode(), o2 = 0, n3 = 0, l2 = s2[0];
for (; void 0 !== l2; ) {
if (o2 === l2.index) {
let i3;
2 === l2.type ? i3 = new R(h2, h2.nextSibling, this, t2) : 1 === l2.type ? i3 = new l2.ctor(h2, l2.name, l2.strings, this, t2) : 6 === l2.type && (i3 = new z(h2, this, t2)), this._$AV.push(i3), l2 = s2[++n3];
}
o2 !== (l2 == null ? void 0 : l2.index) && (h2 = C.nextNode(), o2++);
}
return C.currentNode = r, e2;
}
p(t2) {
let i2 = 0;
for (const s2 of this._$AV) void 0 !== s2 && (void 0 !== s2.strings ? (s2._$AI(t2, s2, i2), i2 += s2.strings.length - 2) : s2._$AI(t2[i2])), i2++;
}
}
class R {
get _$AU() {
var _a2;
return ((_a2 = this._$AM) == null ? void 0 : _a2._$AU) ?? this._$Cv;
}
constructor(t2, i2, s2, e2) {
this.type = 2, this._$AH = E, this._$AN = void 0, this._$AA = t2, this._$AB = i2, this._$AM = s2, this.options = e2, this._$Cv = (e2 == null ? void 0 : e2.isConnected) ?? true;
}
get parentNode() {
let t2 = this._$AA.parentNode;
const i2 = this._$AM;
return void 0 !== i2 && 11 === (t2 == null ? void 0 : t2.nodeType) && (t2 = i2.parentNode), t2;
}
get startNode() {
return this._$AA;
}
get endNode() {
return this._$AB;
}
_$AI(t2, i2 = this) {
t2 = S(this, t2, i2), c(t2) ? t2 === E || null == t2 || "" === t2 ? (this._$AH !== E && this._$AR(), this._$AH = E) : t2 !== this._$AH && t2 !== T && this._(t2) : void 0 !== t2._$litType$ ? this.$(t2) : void 0 !== t2.nodeType ? this.T(t2) : u(t2) ? this.k(t2) : this._(t2);
}
O(t2) {
return this._$AA.parentNode.insertBefore(t2, this._$AB);
}
T(t2) {
this._$AH !== t2 && (this._$AR(), this._$AH = this.O(t2));
}
_(t2) {
this._$AH !== E && c(this._$AH) ? this._$AA.nextSibling.data = t2 : this.T(r.createTextNode(t2)), this._$AH = t2;
}
$(t2) {
var _a2;
const { values: i2, _$litType$: s2 } = t2, e2 = "number" == typeof s2 ? this._$AC(t2) : (void 0 === s2.el && (s2.el = N.createElement(P(s2.h, s2.h[0]), this.options)), s2);
if (((_a2 = this._$AH) == null ? void 0 : _a2._$AD) === e2) this._$AH.p(i2);
else {
const t3 = new M(e2, this), s3 = t3.u(this.options);
t3.p(i2), this.T(s3), this._$AH = t3;
}
}
_$AC(t2) {
let i2 = A.get(t2.strings);
return void 0 === i2 && A.set(t2.strings, i2 = new N(t2)), i2;
}
k(t2) {
a(this._$AH) || (this._$AH = [], this._$AR());
const i2 = this._$AH;
let s2, e2 = 0;
for (const h2 of t2) e2 === i2.length ? i2.push(s2 = new R(this.O(l()), this.O(l()), this, this.options)) : s2 = i2[e2], s2._$AI(h2), e2++;
e2 < i2.length && (this._$AR(s2 && s2._$AB.nextSibling, e2), i2.length = e2);
}
_$AR(t2 = this._$AA.nextSibling, i2) {
var _a2;
for ((_a2 = this._$AP) == null ? void 0 : _a2.call(this, false, true, i2); t2 && t2 !== this._$AB; ) {
const i3 = t2.nextSibling;
t2.remove(), t2 = i3;
}
}
setConnected(t2) {
var _a2;
void 0 === this._$AM && (this._$Cv = t2, (_a2 = this._$AP) == null ? void 0 : _a2.call(this, t2));
}
}
class k {
get tagName() {
return this.element.tagName;
}
get _$AU() {
return this._$AM._$AU;
}
constructor(t2, i2, s2, e2, h2) {
this.type = 1, this._$AH = E, this._$AN = void 0, this.element = t2, this.name = i2, this._$AM = e2, this.options = h2, s2.length > 2 || "" !== s2[0] || "" !== s2[1] ? (this._$AH = Array(s2.length - 1).fill(new String()), this.strings = s2) : this._$AH = E;
}
_$AI(t2, i2 = this, s2, e2) {
const h2 = this.strings;
let o2 = false;
if (void 0 === h2) t2 = S(this, t2, i2, 0), o2 = !c(t2) || t2 !== this._$AH && t2 !== T, o2 && (this._$AH = t2);
else {
const e3 = t2;
let n3, r2;
for (t2 = h2[0], n3 = 0; n3 < h2.length - 1; n3++) r2 = S(this, e3[s2 + n3], i2, n3), r2 === T && (r2 = this._$AH[n3]), o2 || (o2 = !c(r2) || r2 !== this._$AH[n3]), r2 === E ? t2 = E : t2 !== E && (t2 += (r2 ?? "") + h2[n3 + 1]), this._$AH[n3] = r2;
}
o2 && !e2 && this.j(t2);
}
j(t2) {
t2 === E ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t2 ?? "");
}
}
class H extends k {
constructor() {
super(...arguments), this.type = 3;
}
j(t2) {
this.element[this.name] = t2 === E ? void 0 : t2;
}
}
class I extends k {
constructor() {
super(...arguments), this.type = 4;
}
j(t2) {
this.element.toggleAttribute(this.name, !!t2 && t2 !== E);
}
}
class L extends k {
constructor(t2, i2, s2, e2, h2) {
super(t2, i2, s2, e2, h2), this.type = 5;
}
_$AI(t2, i2 = this) {
if ((t2 = S(this, t2, i2, 0) ?? E) === T) return;
const s2 = this._$AH, e2 = t2 === E && s2 !== E || t2.capture !== s2.capture || t2.once !== s2.once || t2.passive !== s2.passive, h2 = t2 !== E && (s2 === E || e2);
e2 && this.element.removeEventListener(this.name, this, s2), h2 && this.element.addEventListener(this.name, this, t2), this._$AH = t2;
}
handleEvent(t2) {
var _a2;
"function" == typeof this._$AH ? this._$AH.call(((_a2 = this.options) == null ? void 0 : _a2.host) ?? this.element, t2) : this._$AH.handleEvent(t2);
}
}
class z {
constructor(t2, i2, s2) {
this.element = t2, this.type = 6, this._$AN = void 0, this._$AM = i2, this.options = s2;
}
get _$AU() {
return this._$AM._$AU;
}
_$AI(t2) {
S(this, t2);
}
}
const j = t.litHtmlPolyfillSupport;
j == null ? void 0 : j(N, R), (t.litHtmlVersions ?? (t.litHtmlVersions = [])).push("3.3.0");
const B = (t2, i2, s2) => {
const e2 = (s2 == null ? void 0 : s2.renderBefore) ?? i2;
let h2 = e2._$litPart$;
if (void 0 === h2) {
const t3 = (s2 == null ? void 0 : s2.renderBefore) ?? null;
e2._$litPart$ = h2 = new R(i2.insertBefore(l(), t3), t3, void 0, s2 ?? {});
}
return h2._$AI(t2), h2;
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const s = globalThis;
class i extends y$1 {
constructor() {
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
}
createRenderRoot() {
var _a2;
const t2 = super.createRenderRoot();
return (_a2 = this.renderOptions).renderBefore ?? (_a2.renderBefore = t2.firstChild), t2;
}
update(t2) {
const r2 = this.render();
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t2), this._$Do = B(r2, this.renderRoot, this.renderOptions);
}
connectedCallback() {
var _a2;
super.connectedCallback(), (_a2 = this._$Do) == null ? void 0 : _a2.setConnected(true);
}
disconnectedCallback() {
var _a2;
super.disconnectedCallback(), (_a2 = this._$Do) == null ? void 0 : _a2.setConnected(false);
}
render() {
return T;
}
}
i._$litElement$ = true, i["finalized"] = true, (_a = s.litElementHydrateSupport) == null ? void 0 : _a.call(s, { LitElement: i });
const o = s.litElementPolyfillSupport;
o == null ? void 0 : o({ LitElement: i });
(s.litElementVersions ?? (s.litElementVersions = [])).push("4.2.0");
export {
E,
f$1 as f,
i,
u$1 as u,
x
};

View File

@@ -0,0 +1,47 @@
import { f, u } from "./lit-z6_uA4GX.mjs";
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const t = (t2) => (e, o2) => {
void 0 !== o2 ? o2.addInitializer(() => {
customElements.define(t2, e);
}) : customElements.define(t2, e);
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const o = { attribute: true, type: String, converter: u, reflect: false, hasChanged: f }, r = (t2 = o, e, r2) => {
const { kind: n2, metadata: i } = r2;
let s = globalThis.litPropertyMetadata.get(i);
if (void 0 === s && globalThis.litPropertyMetadata.set(i, s = /* @__PURE__ */ new Map()), "setter" === n2 && ((t2 = Object.create(t2)).wrapped = true), s.set(r2.name, t2), "accessor" === n2) {
const { name: o2 } = r2;
return { set(r3) {
const n3 = e.get.call(this);
e.set.call(this, r3), this.requestUpdate(o2, n3, t2);
}, init(e2) {
return void 0 !== e2 && this.C(o2, void 0, t2, e2), e2;
} };
}
if ("setter" === n2) {
const { name: o2 } = r2;
return function(r3) {
const n3 = this[o2];
e.call(this, r3), this.requestUpdate(o2, n3, t2);
};
}
throw Error("Unsupported decorator location: " + n2);
};
function n(t2) {
return (e, o2) => "object" == typeof o2 ? r(t2, e, o2) : ((t3, e2, o3) => {
const r2 = e2.hasOwnProperty(o3);
return e2.constructor.createProperty(o3, t3), r2 ? Object.getOwnPropertyDescriptor(e2, o3) : void 0;
})(t2, e, o2);
}
export {
n,
t
};

View File

@@ -1,47 +0,0 @@
import { f as d, u as l } from "./lit-CWlWuEHk.mjs";
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const f = (t) => (r, e) => {
e !== void 0 ? e.addInitializer(() => {
customElements.define(t, r);
}) : customElements.define(t, r);
};
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const p = { attribute: !0, type: String, converter: l, reflect: !1, hasChanged: d }, u = (t = p, r, e) => {
const { kind: i, metadata: a } = e;
let n = globalThis.litPropertyMetadata.get(a);
if (n === void 0 && globalThis.litPropertyMetadata.set(a, n = /* @__PURE__ */ new Map()), i === "setter" && ((t = Object.create(t)).wrapped = !0), n.set(e.name, t), i === "accessor") {
const { name: o } = e;
return { set(s) {
const c = r.get.call(this);
r.set.call(this, s), this.requestUpdate(o, c, t);
}, init(s) {
return s !== void 0 && this.C(o, void 0, t, s), s;
} };
}
if (i === "setter") {
const { name: o } = e;
return function(s) {
const c = this[o];
r.call(this, s), this.requestUpdate(o, c, t);
};
}
throw Error("Unsupported decorator location: " + i);
};
function m(t) {
return (r, e) => typeof e == "object" ? u(t, r, e) : ((i, a, n) => {
const o = a.hasOwnProperty(n);
return a.constructor.createProperty(n, i), o ? Object.getOwnPropertyDescriptor(a, n) : void 0;
})(t, r, e);
}
export {
m as n,
f as t
};

View File

@@ -0,0 +1,128 @@
import { E } from "./lit-z6_uA4GX.mjs";
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const f$1 = (o2) => void 0 === o2.strings;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const t = { CHILD: 2 }, e$1 = (t2) => (...e2) => ({ _$litDirective$: t2, values: e2 });
class i {
constructor(t2) {
}
get _$AU() {
return this._$AM._$AU;
}
_$AT(t2, e2, i2) {
this._$Ct = t2, this._$AM = e2, this._$Ci = i2;
}
_$AS(t2, e2) {
return this.update(t2, e2);
}
update(t2, e2) {
return this.render(...e2);
}
}
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const s = (i2, t2) => {
var _a;
const e2 = i2._$AN;
if (void 0 === e2) return false;
for (const i3 of e2) (_a = i3._$AO) == null ? void 0 : _a.call(i3, t2, false), s(i3, t2);
return true;
}, o$1 = (i2) => {
let t2, e2;
do {
if (void 0 === (t2 = i2._$AM)) break;
e2 = t2._$AN, e2.delete(i2), i2 = t2;
} while (0 === (e2 == null ? void 0 : e2.size));
}, r = (i2) => {
for (let t2; t2 = i2._$AM; i2 = t2) {
let e2 = t2._$AN;
if (void 0 === e2) t2._$AN = e2 = /* @__PURE__ */ new Set();
else if (e2.has(i2)) break;
e2.add(i2), c(t2);
}
};
function h$1(i2) {
void 0 !== this._$AN ? (o$1(this), this._$AM = i2, r(this)) : this._$AM = i2;
}
function n$1(i2, t2 = false, e2 = 0) {
const r2 = this._$AH, h2 = this._$AN;
if (void 0 !== h2 && 0 !== h2.size) if (t2) if (Array.isArray(r2)) for (let i3 = e2; i3 < r2.length; i3++) s(r2[i3], false), o$1(r2[i3]);
else null != r2 && (s(r2, false), o$1(r2));
else s(this, i2);
}
const c = (i2) => {
i2.type == t.CHILD && (i2._$AP ?? (i2._$AP = n$1), i2._$AQ ?? (i2._$AQ = h$1));
};
class f extends i {
constructor() {
super(...arguments), this._$AN = void 0;
}
_$AT(i2, t2, e2) {
super._$AT(i2, t2, e2), r(this), this.isConnected = i2._$AU;
}
_$AO(i2, t2 = true) {
var _a, _b;
i2 !== this.isConnected && (this.isConnected = i2, i2 ? (_a = this.reconnected) == null ? void 0 : _a.call(this) : (_b = this.disconnected) == null ? void 0 : _b.call(this)), t2 && (s(this, i2), o$1(this));
}
setValue(t2) {
if (f$1(this._$Ct)) this._$Ct._$AI(t2, this);
else {
const i2 = [...this._$Ct._$AH];
i2[this._$Ci] = t2, this._$Ct._$AI(i2, this, 0);
}
}
disconnected() {
}
reconnected() {
}
}
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const e = () => new h();
class h {
}
const o = /* @__PURE__ */ new WeakMap(), n = e$1(class extends f {
render(i2) {
return E;
}
update(i2, [s2]) {
var _a;
const e2 = s2 !== this.G;
return e2 && void 0 !== this.G && this.rt(void 0), (e2 || this.lt !== this.ct) && (this.G = s2, this.ht = (_a = i2.options) == null ? void 0 : _a.host, this.rt(this.ct = i2.element)), E;
}
rt(t2) {
if (this.isConnected || (t2 = void 0), "function" == typeof this.G) {
const i2 = this.ht ?? globalThis;
let s2 = o.get(i2);
void 0 === s2 && (s2 = /* @__PURE__ */ new WeakMap(), o.set(i2, s2)), void 0 !== s2.get(this.G) && this.G.call(this.ht, void 0), s2.set(this.G, t2), void 0 !== t2 && this.G.call(this.ht, t2);
} else this.G.value = t2;
}
get lt() {
var _a, _b;
return "function" == typeof this.G ? (_a = o.get(this.ht ?? globalThis)) == null ? void 0 : _a.get(this.G) : (_b = this.G) == null ? void 0 : _b.value;
}
disconnected() {
this.lt === this.ct && this.rt(void 0);
}
reconnected() {
this.rt(this.ct);
}
});
export {
e,
n
};

View File

@@ -1,128 +0,0 @@
import { E as $ } from "./lit-CWlWuEHk.mjs";
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const d = (t) => t.strings === void 0;
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const _ = { CHILD: 2 }, a = (t) => (...s) => ({ _$litDirective$: t, values: s });
class A {
constructor(s) {
}
get _$AU() {
return this._$AM._$AU;
}
_$AT(s, e, i) {
this._$Ct = s, this._$AM = e, this._$Ci = i;
}
_$AS(s, e) {
return this.update(s, e);
}
update(s, e) {
return this.render(...e);
}
}
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const n = (t, s) => {
var i;
const e = t._$AN;
if (e === void 0) return !1;
for (const h of e) (i = h._$AO) == null || i.call(h, s, !1), n(h, s);
return !0;
}, r = (t) => {
let s, e;
do {
if ((s = t._$AM) === void 0) break;
e = s._$AN, e.delete(t), t = s;
} while ((e == null ? void 0 : e.size) === 0);
}, l = (t) => {
for (let s; s = t._$AM; t = s) {
let e = s._$AN;
if (e === void 0) s._$AN = e = /* @__PURE__ */ new Set();
else if (e.has(t)) break;
e.add(t), v(s);
}
};
function f(t) {
this._$AN !== void 0 ? (r(this), this._$AM = t, l(this)) : this._$AM = t;
}
function u(t, s = !1, e = 0) {
const i = this._$AH, h = this._$AN;
if (h !== void 0 && h.size !== 0) if (s) if (Array.isArray(i)) for (let o = e; o < i.length; o++) n(i[o], !1), r(i[o]);
else i != null && (n(i, !1), r(i));
else n(this, t);
}
const v = (t) => {
t.type == _.CHILD && (t._$AP ?? (t._$AP = u), t._$AQ ?? (t._$AQ = f));
};
class p extends A {
constructor() {
super(...arguments), this._$AN = void 0;
}
_$AT(s, e, i) {
super._$AT(s, e, i), l(this), this.isConnected = s._$AU;
}
_$AO(s, e = !0) {
var i, h;
s !== this.isConnected && (this.isConnected = s, s ? (i = this.reconnected) == null || i.call(this) : (h = this.disconnected) == null || h.call(this)), e && (n(this, s), r(this));
}
setValue(s) {
if (d(this._$Ct)) this._$Ct._$AI(s, this);
else {
const e = [...this._$Ct._$AH];
e[this._$Ci] = s, this._$Ct._$AI(e, this, 0);
}
}
disconnected() {
}
reconnected() {
}
}
/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const g = () => new C();
class C {
}
const c = /* @__PURE__ */ new WeakMap(), M = a(class extends p {
render(t) {
return $;
}
update(t, [s]) {
var i;
const e = s !== this.G;
return e && this.G !== void 0 && this.rt(void 0), (e || this.lt !== this.ct) && (this.G = s, this.ht = (i = t.options) == null ? void 0 : i.host, this.rt(this.ct = t.element)), $;
}
rt(t) {
if (this.isConnected || (t = void 0), typeof this.G == "function") {
const s = this.ht ?? globalThis;
let e = c.get(s);
e === void 0 && (e = /* @__PURE__ */ new WeakMap(), c.set(s, e)), e.get(this.G) !== void 0 && this.G.call(this.ht, void 0), e.set(this.G, t), t !== void 0 && this.G.call(this.ht, t);
} else this.G.value = t;
}
get lt() {
var t, s;
return typeof this.G == "function" ? (t = c.get(this.ht ?? globalThis)) == null ? void 0 : t.get(this.G) : (s = this.G) == null ? void 0 : s.value;
}
disconnected() {
this.lt === this.ct && this.rt(void 0);
}
reconnected() {
this.rt(this.ct);
}
});
export {
g as e,
M as n
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -168,6 +168,7 @@ table {
". . color-chip";
grid-template-rows: 12px auto auto auto auto 12px;
grid-template-columns: min-content auto 80px;
row-gap: 4px;
color: inherit;
text-decoration: none;
padding-left: 12px;

View File

@@ -68,10 +68,13 @@
<h2>Calendars</h2>
<ul>
{% for calendar in calendars %}
{% let color = calendar.color.to_owned().unwrap_or("red".to_owned()) %}
{% let color = calendar.color.to_owned().unwrap_or("transparent".to_owned()) %}
<li class="collection-list-item" style="--color: {{ color }}">
<a href="/frontend/user/{{ calendar.principal }}/calendar/{{ calendar.id }}">
<span class="title">{{ calendar.displayname.to_owned().unwrap_or(calendar.id.to_owned()) }}</span>
<span class="title">
{%- if calendar.principal != user.id -%}{{ calendar.principal }}/{%- endif -%}
{{ calendar.displayname.to_owned().unwrap_or(calendar.id.to_owned()) }}
</span>
<div class="comps">
{% for comp in calendar.components %}
<span>{{ comp }}</span>
@@ -87,7 +90,9 @@
<form action="/caldav/principal/{{ calendar.principal }}/{{ calendar.id }}" target="_blank" method="GET">
<button type="submit">Download</button>
</form>
{% if !calendar.id.starts_with("_birthdays_") %}
<delete-button trash href="/caldav/principal/{{ calendar.principal }}/{{ calendar.id }}"></delete-button>
{% endif %}
</div>
<div class="color-chip"></div>
</a>
@@ -100,10 +105,13 @@
<h3>Deleted Calendars</h3>
<ul>
{% for calendar in deleted_calendars %}
{% let color = calendar.color.to_owned().unwrap_or("red".to_owned()) %}
{% let color = calendar.color.to_owned().unwrap_or("transparent".to_owned()) %}
<li class="collection-list-item" style="--color: {{ color }}">
<a href="/frontend/user/{{ calendar.principal }}/calendar/{{ calendar.id}}">
<span class="title">{{ calendar.displayname.to_owned().unwrap_or(calendar.id.to_owned()) }}</span>
<span class="title">
{%- if calendar.principal != user.id -%}{{ calendar.principal }}/{%- endif -%}
{{ calendar.displayname.to_owned().unwrap_or(calendar.id.to_owned()) }}
</span>
<div class="comps">
{% for comp in calendar.components %}
<span>{{ comp }}</span>
@@ -134,7 +142,10 @@
{% for addressbook in addressbooks %}
<li class="collection-list-item">
<a href="/frontend/user/{{ addressbook.principal }}/addressbook/{{ addressbook.id}}">
<span class="title">{{ addressbook.displayname.to_owned().unwrap_or(addressbook.id.to_owned()) }}</span>
<span class="title">
{%- if addressbook.principal != user.id -%}{{ addressbook.principal }}/{%- endif -%}
{{ addressbook.displayname.to_owned().unwrap_or(addressbook.id.to_owned()) }}
</span>
<span class="description">
{% if let Some(description) = addressbook.description %}{{ description }}{% endif %}
</span>
@@ -156,7 +167,10 @@
{% for addressbook in deleted_addressbooks %}
<li class="collection-list-item">
<a href="/frontend/user/{{ addressbook.principal }}/addressbook/{{ addressbook.id}}">
<span class="title">{{ addressbook.displayname.to_owned().unwrap_or(addressbook.id.to_owned()) }}</span>
<span class="title">
{%- if addressbook.principal != user.id -%}{{ addressbook.principal }}/{%- endif -%}
{{ addressbook.displayname.to_owned().unwrap_or(addressbook.id.to_owned()) }}
</span>
<span class="description">
{% if let Some(description) = addressbook.description %}{{ description }}{% endif %}
</span>

View File

@@ -7,6 +7,9 @@ pub enum OidcError {
#[error("Cannot generate redirect url, something's not configured correctly")]
OidcParseError(#[from] ParseError),
#[error("Error fetching user info: {0}")]
UserInfo(String),
#[error(transparent)]
OidcConfigurationError(#[from] ConfigurationError),

View File

@@ -41,7 +41,7 @@ struct OidcState {
#[derive(Debug, Deserialize, Serialize)]
struct GroupAdditionalClaims {
#[serde(default)]
pub groups: Vec<String>,
groups: Option<Vec<String>>,
}
impl openidconnect::AdditionalClaims for GroupAdditionalClaims {}
@@ -190,12 +190,14 @@ pub async fn route_get_oidc_callback<US: UserStore + Clone>(
)?
.request_async(&http_client)
.await
.map_err(|_| OidcError::Other("Error fetching user info"))?;
.map_err(|e| OidcError::UserInfo(e.to_string()))?;
if let Some(require_group) = &oidc_config.require_group {
if !user_info_claims
.additional_claims()
.groups
.clone()
.unwrap_or_default()
.contains(require_group)
{
return Ok((

View File

@@ -3,7 +3,10 @@ mod principal;
use crate::error::Error;
use async_trait::async_trait;
pub use principal::{AppToken, Principal, PrincipalType};
mod principal_type;
pub use principal_type::*;
pub use principal::{AppToken, Principal};
#[async_trait]
pub trait AuthenticationProvider: Send + Sync + 'static {

View File

@@ -1,3 +1,4 @@
use crate::{Secret, auth::PrincipalType};
use axum::{
body::Body,
extract::{FromRequestParts, OptionalFromRequestParts},
@@ -6,67 +7,8 @@ use axum::{
use chrono::{DateTime, Utc};
use derive_more::Display;
use http::{HeaderValue, StatusCode, header};
use rustical_xml::ValueSerialize;
use serde::{Deserialize, Serialize};
use std::{convert::Infallible, fmt::Display};
use crate::Secret;
/// https://datatracker.ietf.org/doc/html/rfc5545#section-3.2.3
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, clap::ValueEnum)]
#[serde(rename_all = "lowercase")]
pub enum PrincipalType {
#[default]
Individual,
Group,
Resource,
Room,
Unknown,
// TODO: X-Name, IANA-token
}
impl TryFrom<&str> for PrincipalType {
type Error = crate::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(match value {
"INDIVIDUAL" => Self::Individual,
"GROUP" => Self::Group,
"RESOURCE" => Self::Resource,
"ROOM" => Self::Room,
"UNKNOWN" => Self::Unknown,
_ => {
return Err(crate::Error::InvalidPrincipalType(
"Invalid principal type".to_owned(),
));
}
})
}
}
impl PrincipalType {
pub fn as_str(&self) -> &'static str {
match self {
PrincipalType::Individual => "INDIVIDUAL",
PrincipalType::Group => "GROUP",
PrincipalType::Resource => "RESOURCE",
PrincipalType::Room => "ROOM",
PrincipalType::Unknown => "UNKNOWN",
}
}
}
impl Display for PrincipalType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl ValueSerialize for PrincipalType {
fn serialize(&self) -> String {
self.to_string()
}
}
use std::convert::Infallible;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AppToken {

View File

@@ -0,0 +1,60 @@
use std::fmt::Display;
use rustical_xml::ValueSerialize;
use serde::{Deserialize, Serialize};
/// https://datatracker.ietf.org/doc/html/rfc5545#section-3.2.3
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, clap::ValueEnum)]
#[serde(rename_all = "lowercase")]
pub enum PrincipalType {
#[default]
Individual,
Group,
Resource,
Room,
Unknown,
// TODO: X-Name, IANA-token
}
impl TryFrom<&str> for PrincipalType {
type Error = crate::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(match value {
"INDIVIDUAL" => Self::Individual,
"GROUP" => Self::Group,
"RESOURCE" => Self::Resource,
"ROOM" => Self::Room,
"UNKNOWN" => Self::Unknown,
_ => {
return Err(crate::Error::InvalidPrincipalType(
"Invalid principal type".to_owned(),
));
}
})
}
}
impl PrincipalType {
pub fn as_str(&self) -> &'static str {
match self {
PrincipalType::Individual => "INDIVIDUAL",
PrincipalType::Group => "GROUP",
PrincipalType::Resource => "RESOURCE",
PrincipalType::Room => "ROOM",
PrincipalType::Unknown => "UNKNOWN",
}
}
}
impl Display for PrincipalType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl ValueSerialize for PrincipalType {
fn serialize(&self) -> String {
self.to_string()
}
}

View File

@@ -11,6 +11,9 @@ mod secret;
mod subscription_store;
pub mod synctoken;
#[cfg(test)]
pub mod tests;
pub use addressbook_store::AddressbookStore;
pub use calendar_store::CalendarStore;
pub use combined_calendar_store::CombinedCalendarStore;

View File

View File

@@ -1,35 +0,0 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Ximian//NONSGML Evolution Calendar//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T020000
RRULE:FREQ=YEARLY;UNTIL=20370329T010000Z;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T030000
RRULE:FREQ=YEARLY;UNTIL=20361026T010000Z;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
UID:67d830c3e681950b6a12f7c287b316269a19fcf7
DTSTAMP:20230831T102923Z
DTSTART;TZID=Europe/Berlin:20230829T043000
DTEND;TZID=Europe/Berlin:20230829T045500
SEQUENCE:2
SUMMARY:asdjlk
TRANSP:OPAQUE
CLASS:PUBLIC
CREATED:20230831T103040Z
LAST-MODIFIED:20230831T103040Z
END:VEVENT
END:VCALENDAR

View File

@@ -1,109 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:Europe/Berlin
LAST-MODIFIED:20230104T023643Z
TZURL:https://www.tzurl.org/zoneinfo/Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
X-PROLEPTIC-TZNAME:LMT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+005328
TZOFFSETTO:+0100
DTSTART:18930401T000632
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19160430T230000
RDATE:19400401T020000
RDATE:19430329T020000
RDATE:19460414T020000
RDATE:19470406T030000
RDATE:19480418T020000
RDATE:19490410T020000
RDATE:19800406T020000
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19161001T010000
RDATE:19421102T030000
RDATE:19431004T030000
RDATE:19441002T030000
RDATE:19451118T030000
RDATE:19461007T030000
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19170416T020000
RRULE:FREQ=YEARLY;UNTIL=19180415T010000Z;BYMONTH=4;BYDAY=3MO
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19170917T030000
RRULE:FREQ=YEARLY;UNTIL=19180916T010000Z;BYMONTH=9;BYDAY=3MO
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19440403T020000
RRULE:FREQ=YEARLY;UNTIL=19450402T010000Z;BYMONTH=4;BYDAY=1MO
END:DAYLIGHT
BEGIN:DAYLIGHT
TZNAME:CEMT
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
DTSTART:19450524T010000
RDATE:19470511T020000
END:DAYLIGHT
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
DTSTART:19450924T030000
RDATE:19470629T030000
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0100
TZOFFSETTO:+0100
DTSTART:19460101T000000
RDATE:19800101T000000
END:STANDARD
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19471005T030000
RRULE:FREQ=YEARLY;UNTIL=19491002T010000Z;BYMONTH=10;BYDAY=1SU
END:STANDARD
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19800928T030000
RRULE:FREQ=YEARLY;UNTIL=19950924T010000Z;BYMONTH=9;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19810329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19961027T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

View File

@@ -1,46 +0,0 @@
// use rstest::rstest;
// use rstest_reuse::{self, apply, template};
// use rustical_store::{CalendarObject, CalendarStore};
// use rustical_store_sqlite::{calendar_store::SqliteCalendarStore, create_test_db};
//
// const TIMEZONE: &str = include_str!("examples/timezone.ics");
// const EVENT: &str = include_str!("examples/event.ics");
//
// #[template]
// #[rstest]
// #[case::sqlite(async {
// let (send, _recv) = tokio::sync::mpsc::channel(100);
// SqliteCalendarStore::new(create_test_db().await.unwrap(), send)
// })]
// async fn cal_store<CS: CalendarStore>(
// #[future(awt)]
// #[case]
// mut store: CS,
// ) {
// }
// TODO: Reimplement, add test principal
// #[apply(cal_store)]
// #[tokio::test]
// async fn test_create_event<CS: CalendarStore>(store: CS) {
// store
// .insert_calendar(rustical_store::Calendar {
// id: "test".to_owned(),
// displayname: Some("Test Calendar".to_owned()),
// principal: "testuser".to_owned(),
// timezone: Some(TIMEZONE.to_owned()),
// ..Default::default() // timezone: TIMEZONE.to_owned(),
// })
// .await
// .unwrap();
//
// let object = CalendarObject::from_ics("asd".to_owned(), EVENT.to_owned()).unwrap();
// store
// .put_object("testuser".to_owned(), "test".to_owned(), object, true)
// .await
// .unwrap();
//
// let event = store.get_object("testuser", "test", "asd").await.unwrap();
// assert_eq!(event.get_ics(), EVENT);
// assert_eq!(event.get_id(), "asd");
// }

View File

@@ -7,6 +7,9 @@ repository.workspace = true
license.workspace = true
publish = false
[features]
test = []
[dependencies]
tokio.workspace = true
rustical_store = { workspace = true }

View File

@@ -8,6 +8,9 @@ pub mod error;
pub mod principal_store;
pub mod subscription_store;
#[cfg(any(test, feature = "test"))]
pub mod tests;
#[derive(Debug, Clone, Serialize, sqlx::Type)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum ChangeOperation {
@@ -42,13 +45,3 @@ pub async fn create_db_pool(db_url: &str, migrate: bool) -> Result<Pool<Sqlite>,
}
Ok(db)
}
pub async fn create_test_db() -> Result<SqlitePool, sqlx::Error> {
let db = SqlitePool::connect("sqlite::memory:").await?;
sqlx::migrate!("./migrations").run(&db).await?;
Ok(db)
}
pub async fn create_test_store() -> Result<SqliteStore, sqlx::Error> {
Ok(SqliteStore::new(create_test_db().await?))
}

View File

@@ -0,0 +1,42 @@
use crate::{
SqliteStore, addressbook_store::SqliteAddressbookStore, calendar_store::SqliteCalendarStore,
principal_store::SqlitePrincipalStore,
};
use rustical_store::{
AddressbookStore, CalendarStore, CollectionOperation, SubscriptionStore,
auth::AuthenticationProvider,
};
use sqlx::SqlitePool;
use std::sync::Arc;
use tokio::sync::mpsc::Receiver;
pub async fn get_test_stores() -> (
Arc<impl AddressbookStore>,
Arc<impl CalendarStore>,
Arc<impl SubscriptionStore>,
Arc<impl AuthenticationProvider>,
Receiver<CollectionOperation>,
) {
let db = SqlitePool::connect("sqlite::memory:").await.unwrap();
sqlx::migrate!("./migrations").run(&db).await.unwrap();
// let db = create_db_pool("sqlite::memory:", true).await.unwrap();
// Channel to watch for changes (for DAV Push)
let (send, recv) = tokio::sync::mpsc::channel(1000);
let addressbook_store = Arc::new(SqliteAddressbookStore::new(db.clone(), send.clone()));
let cal_store = Arc::new(SqliteCalendarStore::new(db.clone(), send));
let subscription_store = Arc::new(SqliteStore::new(db.clone()));
let principal_store = Arc::new(SqlitePrincipalStore::new(db.clone()));
(
addressbook_store,
cal_store,
subscription_store,
principal_store,
recv,
)
}
#[tokio::test]
async fn test_create_store() {
get_test_stores().await;
}

View File

@@ -0,0 +1,7 @@
# Frontend
The frontend is currently generated through [askama templates](https://askama.readthedocs.io/en/stable/) for server-side rendered pages
and uses Web Components for interactive elements.
Normally, content that will be statically served by the frontend module (i.e. stylesheet and web components) is embedded into the binary.
Using the `frontend-dev` feature you can serve it from source to see changes without recompiling RustiCal.

View File

@@ -3,11 +3,11 @@
Collection of RFCs relevant to this project
- Versioning Extensions to WebDAV: [RFC 3253](https://datatracker.ietf.org/doc/html/rfc3253)
- provides the REPORT method
- provides the REPORT method
- Calendaring Extensions to WebDAV (CalDAV): [RFC 4791](https://datatracker.ietf.org/doc/html/rfc4791)
- Scheduling Extensions to CalDAV: [RFC 6638](https://datatracker.ietf.org/doc/html/rfc6638)
- not sur`e yet whether to implement this
- not sure yet whether to implement this
- Collection Synchronization WebDAV [RFC 6578](https://datatracker.ietf.org/doc/html/rfc6578)
- We need to implement sync-token, etc.
- This is important for more efficient synchronisation
- We need to implement sync-token, etc.
- This is important for more efficient synchronisation
- iCalendar [RFC 2445](https://datatracker.ietf.org/doc/html/rfc2445#section-3.10)

View File

@@ -3,10 +3,10 @@
a CalDAV/CardDAV server
!!! warning
RustiCal is **not production-ready!**
I've been using it for the last few weeks and I'm slowly becoming more confident,
however you'd be one of the first testers so expect bugs and rough edges.
If you still want to play around with it in its current state, absolutely feel free to do so and to open up an issue if something is not working. :)
RustiCal is **not production-ready!**
I've been using it for the last few weeks and I'm slowly becoming more confident,
however you'd be one of the first testers so expect bugs and rough edges.
If you still want to play around with it in its current state, absolutely feel free to do so and to open up an issue if something is not working. :)
## Features

View File

@@ -0,0 +1,31 @@
# Configuration
While RustiCal (apart from user management) will work without any configuration you should still know how to configure it. :)
You can either mount a `config.toml` file or use environment variables (recommended).
To see the options you can generate a default configuration using
```sh title="Generate default config.toml"
rustical gen-config
```
To see all configuration options available you can browse the [Cargo docs](/rustical/_crate/rustical/config/struct.Config.html).
## Environment variables
The options in `config.toml` can also be configured using environment variables.
Names translate the following:
```toml title="Example config.toml"
[data_store.toml]
path = "asd"
```
becomes `RUSTICAL_DATA_STORE__TOML__PATH`.
Every variable is
- uppercase
- prefixed by `RUSTICAL_`
- Dots become `__`
- Arrays are JSON-encoded

View File

@@ -40,38 +40,6 @@ App tokens are used by your CalDAV/CardDAV client (which can be managed through
I recommend to generate random app tokens for each CalDAV/CardDAV client.
Since the app tokens are random they use the faster `pbkdf2` algorithm.
## Configuration
While RustiCal (apart from user management) will work without any configuration you should still know how to configure it. :)
You can either mount a `config.toml` file or use environment variables.
To see the options you can generate a default configuration using
```sh title="Generate default config.toml"
rustical gen-config
```
To see all configuration options available you can browse the [Cargo docs](/rustical/_crate/rustical/config/struct.Config.html).
### Environment variables
The options in `config.toml` can also be configured using environment variables.
Names translate the following:
```toml title="Example config.toml"
[data_store.toml]
path = "asd"
```
becomes `RUSTICAL_DATA_STORE__TOML__PATH`.
Every variable is
- uppercase
- prefixed by `RUSTICAL_`
- Dots become `__`
- Arrays are JSON-encoded
## Manual
```sh

10
docs/style.css Normal file
View File

@@ -0,0 +1,10 @@
body .md-main {
h1 {
font-weight: bold;
color: var(--md-typeset-color);
}
}
.md-tabs {
box-shadow: 0px 0 20px -10px black;
}

View File

@@ -14,7 +14,7 @@ theme:
name: Switch to light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
primary: white
accent: indigo
toggle:
icon: material/toggle-switch
@@ -38,6 +38,13 @@ theme:
- content.tooltips
- navigation.indices
- navigation.tabs
- navigation.indexes
- navigation.indexes
- navigation.instant
- navigation.footer
extra_css:
- style.css
markdown_extensions:
- fenced_code
@@ -58,10 +65,13 @@ markdown_extensions:
nav:
- Home: index.md
- Installation: installation.md
- Installation:
- installation/index.md
- Configuration: installation/configuration.md
- OpenID Connect: setup/oidc.md
- Developers:
- developers/index.md
- Relevant RFCs: developers/rfcs.md
- Frontend: developers/frontend.md
- Debugging: developers/debugging.md
- Cargo docs: /rustical/_crate/rustical/