Compare commits

...

12 Commits

Author SHA1 Message Date
Lennart K
dde05d2f45 Workflow: Publish container images for feature branches too 2026-01-16 16:29:38 +01:00
Lennart K
f503bf2bf7 Update quick-xml 2026-01-16 15:47:10 +01:00
Lennart K
d84158e8ad version 0.11.17 2026-01-16 12:26:43 +01:00
Lennart K
7ef566040a Disable a test that will be fixed in 0.12 2026-01-16 12:16:02 +01:00
Lennart K
1c1f0c6da2 Update ical-rs@dev to fix cargo vendor 2026-01-16 12:10:10 +01:00
Lennart
3fafbd22f4 version 0.11.16 2026-01-15 23:43:00 +01:00
Lennart
e68dc921e6 Now actually fix builds 2026-01-15 23:19:35 +01:00
Lennart
60b45e70ad fix docker builds 2026-01-15 22:31:40 +01:00
Lennart
a0c33c82dd version 0.11.14 2026-01-15 13:32:45 +01:00
Lennart
8ae5e46abf Automatic repair for calendar objects with invalid VERSION:4.0 2026-01-15 13:30:14 +01:00
Lennart
48b2e614a8 Suppress ical invalid version error 2026-01-15 11:15:20 +01:00
Lennart K
f26214abb9 build Docker images for dev branch 2026-01-12 11:15:08 +01:00
17 changed files with 299 additions and 143 deletions

View File

@@ -2,7 +2,10 @@ name: Docker
on:
push:
branches: ["main"]
branches:
- main
- dev
- feat/*
release:
types: ["published"]
@@ -45,7 +48,8 @@ jobs:
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
${{ github.ref_name == 'main' && 'type=ref,event=branch' || '' }}
type=ref,event=branch,prefix=br-
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "DELETE FROM calendarobjectchangelog WHERE (principal, cal_id, object_id) = (?, ?, ?);",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "146e23ae4e0eaae4d65ac7563c67d4f295ccc2534dcc4b3bd710de773ed137f9"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "UPDATE calendarobjects SET ics = ? WHERE (principal, cal_id, id) = (?, ?, ?);",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "354decac84758c88280f60fbf0f93dddc6c7ff92ac7b8ba44049d31df3c680e3"
}

View File

@@ -0,0 +1,38 @@
{
"db_name": "SQLite",
"query": "SELECT principal, cal_id, id, ics FROM calendarobjects WHERE ics LIKE '%VERSION:4.0%';",
"describe": {
"columns": [
{
"name": "principal",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "cal_id",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "id",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "ics",
"ordinal": 3,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "bdaa4bee8b01d0e3773e34672ed4805d1e71d24888f2227045afd90bf080fc23"
}

179
Cargo.lock generated
View File

@@ -477,9 +477,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.8.2"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "basic-toml"
@@ -595,9 +595,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.42"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
dependencies = [
"iana-time-zone",
"js-sys",
@@ -689,9 +689,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.7.6"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "colorchoice"
@@ -1422,9 +1422,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"js-sys",
@@ -1771,14 +1771,13 @@ dependencies = [
[[package]]
name = "ical"
version = "0.11.0"
source = "git+https://github.com/lennart-k/ical-rs?branch=dev#b1edcdf2bb7db5a302a5df3650218a9a16aefe0c"
source = "git+https://github.com/lennart-k/ical-rs?rev=7c2ab1f3#7c2ab1f3abdca768f22d8a36627eebbdd7947e29"
dependencies = [
"chrono",
"chrono-tz",
"derive_more",
"itertools 0.14.0",
"lazy_static",
"phf 0.13.1",
"regex",
"rrule",
"thiserror 2.0.17",
@@ -1786,14 +1785,15 @@ dependencies = [
[[package]]
name = "ical"
version = "0.11.0"
source = "git+https://github.com/lennart-k/ical-rs#dcd3b106758a054f46a5172103abb17972ad032d"
version = "0.12.0-dev"
source = "git+https://github.com/lennart-k/ical-rs?branch=dev#d2226f6b92fa45dcc5a243adc57e6a07a67741a8"
dependencies = [
"chrono",
"chrono-tz",
"derive_more",
"itertools 0.14.0",
"lazy_static",
"phf 0.13.1",
"regex",
"rrule",
"thiserror 2.0.17",
@@ -1938,9 +1938,9 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
[[package]]
name = "insta"
version = "1.46.0"
version = "1.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b66886d14d18d420ab5052cbff544fc5d34d0b2cdd35eb5976aaa10a4a472e5"
checksum = "248b42847813a1550dafd15296fd9748c651d0c32194559dbc05d804d54b21e8"
dependencies = [
"console",
"once_cell",
@@ -2006,9 +2006,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "js-sys"
version = "0.3.83"
version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2257,7 +2257,7 @@ checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d"
dependencies = [
"base64 0.22.1",
"chrono",
"getrandom 0.2.16",
"getrandom 0.2.17",
"http",
"rand 0.8.5",
"reqwest",
@@ -2536,7 +2536,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524"
dependencies = [
"argon2",
"getrandom 0.2.16",
"getrandom 0.2.17",
"password-hash",
"pbkdf2",
"rand_core 0.6.4",
@@ -2862,9 +2862,9 @@ dependencies = [
[[package]]
name = "prost"
version = "0.14.1"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
dependencies = [
"bytes",
"prost-derive",
@@ -2872,9 +2872,9 @@ dependencies = [
[[package]]
name = "prost-derive"
version = "0.14.1"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -2885,9 +2885,9 @@ dependencies = [
[[package]]
name = "quick-xml"
version = "0.38.4"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
checksum = "f2e3bf4aa9d243beeb01a7b3bc30b77cfe2c44e24ec02d751a7104a53c2c49a1"
dependencies = [
"memchr",
]
@@ -2980,7 +2980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"rand_core 0.9.5",
]
[[package]]
@@ -3000,7 +3000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.3",
"rand_core 0.9.5",
]
[[package]]
@@ -3009,14 +3009,14 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.16",
"getrandom 0.2.17",
]
[[package]]
name = "rand_core"
version = "0.9.3"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
@@ -3175,7 +3175,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.16",
"getrandom 0.2.17",
"libc",
"untrusted",
"windows-sys 0.52.0",
@@ -3277,9 +3277,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.9.0"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca"
checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@@ -3288,9 +3288,9 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.9.0"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2"
checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
dependencies = [
"proc-macro2",
"quote",
@@ -3301,9 +3301,9 @@ dependencies = [
[[package]]
name = "rust-embed-utils"
version = "8.9.0"
version = "8.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475"
checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
dependencies = [
"sha2",
"walkdir",
@@ -3311,9 +3311,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.26"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
@@ -3332,7 +3332,7 @@ dependencies = [
[[package]]
name = "rustical"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"anyhow",
"argon2",
@@ -3343,7 +3343,7 @@ dependencies = [
"figment",
"headers",
"http",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs?branch=dev)",
"ical 0.12.0-dev",
"insta",
"opentelemetry",
"opentelemetry-otlp",
@@ -3378,7 +3378,7 @@ dependencies = [
[[package]]
name = "rustical_caldav"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-std",
"async-trait",
@@ -3391,7 +3391,7 @@ dependencies = [
"futures-util",
"headers",
"http",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs)",
"ical 0.11.0",
"insta",
"percent-encoding",
"quick-xml",
@@ -3420,7 +3420,7 @@ dependencies = [
[[package]]
name = "rustical_carddav"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-trait",
"axum",
@@ -3430,7 +3430,7 @@ dependencies = [
"derive_more",
"futures-util",
"http",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs)",
"ical 0.11.0",
"insta",
"percent-encoding",
"quick-xml",
@@ -3454,7 +3454,7 @@ dependencies = [
[[package]]
name = "rustical_dav"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-trait",
"axum",
@@ -3463,7 +3463,7 @@ dependencies = [
"futures-util",
"headers",
"http",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs)",
"ical 0.11.0",
"itertools 0.14.0",
"log",
"matchit 0.9.1",
@@ -3480,7 +3480,7 @@ dependencies = [
[[package]]
name = "rustical_dav_push"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-trait",
"axum",
@@ -3505,7 +3505,7 @@ dependencies = [
[[package]]
name = "rustical_frontend"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"askama",
"askama_web",
@@ -3541,13 +3541,13 @@ dependencies = [
[[package]]
name = "rustical_ical"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"axum",
"chrono",
"chrono-tz",
"derive_more",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs)",
"ical 0.11.0",
"regex",
"rrule",
"rstest",
@@ -3560,7 +3560,7 @@ dependencies = [
[[package]]
name = "rustical_oidc"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-trait",
"axum",
@@ -3576,7 +3576,7 @@ dependencies = [
[[package]]
name = "rustical_store"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"anyhow",
"async-trait",
@@ -3588,7 +3588,7 @@ dependencies = [
"futures-core",
"headers",
"http",
"ical 0.11.0 (git+https://github.com/lennart-k/ical-rs)",
"ical 0.11.0",
"regex",
"rrule",
"rstest",
@@ -3609,7 +3609,7 @@ dependencies = [
[[package]]
name = "rustical_store_sqlite"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"async-trait",
"chrono",
@@ -3618,6 +3618,7 @@ dependencies = [
"password-auth",
"password-hash",
"pbkdf2",
"regex",
"rstest",
"rustical_ical",
"rustical_store",
@@ -3632,7 +3633,7 @@ dependencies = [
[[package]]
name = "rustical_xml"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"quick-xml",
"thiserror 2.0.17",
@@ -3668,9 +3669,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.13.2"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
checksum = "4910321ebe4151be888e35fe062169554e74aad01beafed60410131420ceffbc"
dependencies = [
"web-time",
"zeroize",
@@ -4368,30 +4369,30 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.44"
version = "0.3.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca"
[[package]]
name = "time-macros"
version = "0.2.24"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd"
dependencies = [
"num-conv",
"time-core",
@@ -4626,9 +4627,9 @@ dependencies = [
[[package]]
name = "tower"
version = "0.5.2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
@@ -4796,16 +4797,13 @@ dependencies = [
[[package]]
name = "tracing-opentelemetry"
version = "0.32.0"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e"
checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc"
dependencies = [
"js-sys",
"opentelemetry",
"opentelemetry_sdk",
"rustversion",
"smallvec",
"thiserror 2.0.17",
"tracing",
"tracing-core",
"tracing-log",
@@ -5002,9 +5000,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
version = "1.0.2+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
dependencies = [
"wit-bindgen",
]
@@ -5017,9 +5015,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
version = "0.2.106"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
dependencies = [
"cfg-if",
"once_cell",
@@ -5030,11 +5028,12 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.56"
version = "0.4.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
dependencies = [
"cfg-if",
"futures-util",
"js-sys",
"once_cell",
"wasm-bindgen",
@@ -5043,9 +5042,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.106"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5053,9 +5052,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.106"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -5066,18 +5065,18 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.106"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.83"
version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5444,9 +5443,9 @@ dependencies = [
[[package]]
name = "wit-bindgen"
version = "0.46.0"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
[[package]]
name = "writeable"
@@ -5456,7 +5455,7 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "xml_derive"
version = "0.11.11"
version = "0.11.17"
dependencies = [
"darling 0.23.0",
"heck",
@@ -5577,6 +5576,6 @@ dependencies = [
[[package]]
name = "zmij"
version = "1.0.12"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"

View File

@@ -2,7 +2,7 @@
members = ["crates/*"]
[workspace.package]
version = "0.11.11"
version = "0.11.17"
rust-version = "1.92"
edition = "2024"
description = "A CalDAV server"
@@ -73,7 +73,7 @@ tokio = { version = "1.48", features = [
url = "2.5"
base64 = "0.22"
thiserror = "2.0"
quick-xml = { version = "0.38" }
quick-xml = { version = "0.39" }
rust-embed = "8.9"
tower-sessions = "0.14"
futures-core = "0.3"
@@ -107,9 +107,7 @@ strum = "0.27"
strum_macros = "0.27"
serde_json = { version = "1.0", features = ["raw_value"] }
sqlx-sqlite = { version = "0.8", features = ["bundled"] }
ical = { git = "https://github.com/lennart-k/ical-rs", features = [
"chrono-tz",
] }
ical = { git = "https://github.com/lennart-k/ical-rs", rev = "7c2ab1f3" }
toml = "0.9"
tower = "0.5"
tower-http = { version = "0.6", features = [

View File

@@ -36,7 +36,7 @@ COPY --from=planner /rustical/recipe.json recipe.json
RUN cargo chef cook --release --target "$(cat /tmp/rust_target)"
COPY . .
RUN cargo install --target "$(cat /tmp/rust_target)" --path .
RUN cargo install --locked --target "$(cat /tmp/rust_target)" --path .
FROM scratch
COPY --from=builder /usr/local/cargo/bin/rustical /usr/local/bin/rustical

View File

@@ -45,7 +45,7 @@ impl<PN: XmlDeserialize> XmlDeserialize for PropElement<PN> {
// start of a child element
Event::Start(start) | Event::Empty(start) => {
let empty = matches!(event, Event::Empty(_));
let (ns, name) = reader.resolve_element(start.name());
let (ns, name) = reader.resolver().resolve_element(start.name());
let ns = match ns {
ResolveResult::Bound(ns) => Some(NamespaceOwned::from(ns)),
ResolveResult::Unknown(_ns) => todo!("handle error"),

View File

@@ -349,37 +349,38 @@ UID:abcd3
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT"];
#[rstest]
#[case(ICS_1, EXPANDED_1, None, None)]
// from https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.3
#[case(ICS_2, EXPANDED_2,
Some(CalDateTime::parse("20060103T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc()),
Some(CalDateTime::parse("20060105T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc())
)]
#[case(ICS_3, EXPANDED_3,
Some(CalDateTime::parse("20060103T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc()),
Some(CalDateTime::parse("20060105T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc())
)]
fn test_expand_recurrence(
#[case] ics: &'static str,
#[case] expanded: &[&str],
#[case] from: Option<DateTime<Utc>>,
#[case] to: Option<DateTime<Utc>>,
) {
let event = CalendarObject::from_ics(ics.to_string(), None).unwrap();
let crate::CalendarObjectComponent::Event(event, overrides) = event.get_data() else {
panic!()
};
let events: Vec<String> = event
.expand_recurrence(from, to, overrides)
.unwrap()
.into_iter()
.map(|event| Emitter::generate(&event))
.collect();
assert_eq!(events.len(), expanded.len());
for (output, reference) in events.iter().zip(expanded) {
similar_asserts::assert_eq!(output, reference);
}
}
// The implementation never was entirely correct but will be fixed in v0.12
// #[rstest]
// #[case(ICS_1, EXPANDED_1, None, None)]
// // from https://datatracker.ietf.org/doc/html/rfc4791#section-7.8.3
// #[case(ICS_2, EXPANDED_2,
// Some(CalDateTime::parse("20060103T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc()),
// Some(CalDateTime::parse("20060105T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc())
// )]
// #[case(ICS_3, EXPANDED_3,
// Some(CalDateTime::parse("20060103T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc()),
// Some(CalDateTime::parse("20060105T000000Z", Some(chrono_tz::US::Eastern)).unwrap().utc())
// )]
// fn test_expand_recurrence(
// #[case] ics: &'static str,
// #[case] expanded: &[&str],
// #[case] from: Option<DateTime<Utc>>,
// #[case] to: Option<DateTime<Utc>>,
// ) {
// let event = CalendarObject::from_ics(ics.to_string(), None).unwrap();
// let crate::CalendarObjectComponent::Event(event, overrides) = event.get_data() else {
// panic!()
// };
//
// let events: Vec<String> = event
// .expand_recurrence(from, to, overrides)
// .unwrap()
// .into_iter()
// .map(|event| Emitter::generate(&event))
// .collect();
// assert_eq!(events.len(), expanded.len());
// for (output, reference) in events.iter().zip(expanded) {
// similar_asserts::assert_eq!(output, reference);
// }
// }
}

View File

@@ -36,3 +36,4 @@ pbkdf2.workspace = true
rustical_ical.workspace = true
rstest = { workspace = true, optional = true }
sha2.workspace = true
regex.workspace = true

View File

@@ -3,6 +3,7 @@ use crate::BEGIN_IMMEDIATE;
use async_trait::async_trait;
use chrono::TimeDelta;
use derive_more::derive::Constructor;
use regex::Regex;
use rustical_ical::{CalDateTime, CalendarObject, CalendarObjectType};
use rustical_store::calendar_store::CalendarQuery;
use rustical_store::synctoken::format_synctoken;
@@ -145,6 +146,83 @@ impl SqliteCalendarStore {
}
}
/// In the past exports generated objects with invalid VERSION:4.0
/// This repair sets them to VERSION:2.0
#[allow(clippy::missing_panics_doc)]
pub async fn repair_invalid_version_4_0(&self) -> Result<(), Error> {
struct Row {
principal: String,
cal_id: String,
id: String,
ics: String,
}
let mut tx = self
.db
.begin_with(BEGIN_IMMEDIATE)
.await
.map_err(crate::Error::from)?;
#[allow(clippy::missing_panics_doc)]
let version_pattern = Regex::new(r"(?mi)^VERSION:4.0").unwrap();
let repairs: Vec<Row> = sqlx::query_as!(
Row,
r#"SELECT principal, cal_id, id, ics FROM calendarobjects WHERE ics LIKE '%VERSION:4.0%';"#
)
.fetch_all(&mut *tx)
.await
.map_err(crate::Error::from)?
.into_iter()
.filter_map(|mut row| {
version_pattern.find(&row.ics)?;
let new_ics = version_pattern.replace(&row.ics, "VERSION:2.0");
// Safeguard that we really only changed the version
assert_eq!(row.ics.len(), new_ics.len());
row.ics = new_ics.to_string();
Some(row)
})
.collect();
if repairs.is_empty() {
return Ok(());
}
warn!(
"Found {} calendar objects with invalid VERSION:4.0. Repairing by setting to VERSION:2.0",
repairs.len()
);
for repair in &repairs {
// calendarobjectchangelog is used by sync-collection to fetch changes
// By deleting entries we will later regenerate new entries such that clients will notice
// the objects have changed
warn!(
"Repairing VERSION for {}/{}/{}.ics",
repair.principal, repair.cal_id, repair.id
);
sqlx::query!(
"DELETE FROM calendarobjectchangelog WHERE (principal, cal_id, object_id) = (?, ?, ?);",
repair.principal, repair.cal_id, repair.id
).execute(&mut *tx).await
.map_err(crate::Error::from)?;
sqlx::query!(
"UPDATE calendarobjects SET ics = ? WHERE (principal, cal_id, id) = (?, ?, ?);",
repair.ics,
repair.principal,
repair.cal_id,
repair.id
)
.execute(&mut *tx)
.await
.map_err(crate::Error::from)?;
}
tx.commit().await.map_err(crate::Error::from)?;
Ok(())
}
// Commit "orphaned" objects to the changelog table
pub async fn repair_orphans(&self) -> Result<(), Error> {
struct Row {

View File

@@ -136,7 +136,7 @@ impl NamedStruct {
#(#builder_field_inits),*
};
let (ns, name) = reader.resolve_element(start.name());
let (ns, name) = reader.resolver().resolve_element(start.name());
#(#tagname_field_branches);*
#(#namespace_field_branches);*
@@ -161,7 +161,7 @@ impl NamedStruct {
// start of a child element
Event::Start(start) | Event::Empty(start) => {
let empty = matches!(event, Event::Empty(_));
let (ns, name) = reader.resolve_element(start.name());
let (ns, name) = reader.resolver().resolve_element(start.name());
match (ns, name.as_ref()) {
#(#named_field_branches),*
#(#untagged_field_branches),*

View File

@@ -42,7 +42,7 @@ impl<T: XmlRootTag + XmlDeserialize> XmlDocument for T {
match event {
Event::Decl(_) | Event::Comment(_) => { /* ignore this */ }
Event::Start(start) | Event::Empty(start) => {
let (ns, name) = reader.resolve_element(start.name());
let (ns, name) = reader.resolver().resolve_element(start.name());
let matches = match (Self::root_ns(), &ns, name) {
// Wrong tag
(_, _, name) if name.as_ref() != Self::root_tag().as_bytes() => false,

View File

@@ -17,6 +17,7 @@ pub fn cmd_gen_config(_args: GenConfigArgs) -> anyhow::Result<()> {
http: HttpConfig::default(),
data_store: DataStoreConfig::Sqlite(SqliteDataStoreConfig {
db_url: "/var/lib/rustical/db.sqlite3".to_owned(),
run_repairs: true,
}),
tracing: TracingConfig::default(),
frontend: FrontendConfig {

View File

@@ -26,6 +26,8 @@ impl Default for HttpConfig {
#[serde(deny_unknown_fields)]
pub struct SqliteDataStoreConfig {
pub db_url: String,
#[serde(default = "default_true")]
pub run_repairs: bool,
}
#[derive(Debug, Deserialize, Serialize)]

View File

@@ -70,15 +70,22 @@ async fn get_data_stores(
Receiver<CollectionOperation>,
)> {
Ok(match &config {
DataStoreConfig::Sqlite(SqliteDataStoreConfig { db_url }) => {
DataStoreConfig::Sqlite(SqliteDataStoreConfig {
db_url,
run_repairs,
}) => {
let db = create_db_pool(db_url, migrate).await?;
// 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()));
addressbook_store.repair_orphans().await?;
let cal_store = Arc::new(SqliteCalendarStore::new(db.clone(), send));
cal_store.repair_orphans().await?;
if *run_repairs {
info!("Running repair tasks");
addressbook_store.repair_orphans().await?;
cal_store.repair_invalid_version_4_0().await?;
cal_store.repair_orphans().await?;
}
let subscription_store = Arc::new(SqliteStore::new(db.clone()));
let principal_store = Arc::new(SqlitePrincipalStore::new(db));
(
@@ -119,7 +126,9 @@ async fn main() -> Result<()> {
get_data_stores(!args.no_migrations, &config.data_store).await?;
warn!(
"Validating calendar data against the next-version ical parser.\nIn the next major release these will be rejected and cause errors.\nIf any errors occur, please open an issue so they can be fixed before the next major release."
"Validating calendar data against the next-version ical parser.
In the next major release these will be rejected and cause errors.
If any errors occur, please open an issue so they can be fixed before the next major release."
);
validate_calendar_objects_0_12(principal_store.as_ref(), cal_store.as_ref()).await?;
validate_address_objects_0_12(principal_store.as_ref(), addr_store.as_ref()).await?;

View File

@@ -12,9 +12,10 @@ pub async fn validate_calendar_objects_0_12(
.get_objects(&calendar.principal, &calendar.id)
.await?
{
if let Err(err) =
ical_dev::parser::ical::IcalObjectParser::new(object.get_ics().as_bytes())
.expect_one()
if let Err(err) = ical_dev::parser::ical::IcalObjectParser::from_slice(
object.get_ics().as_bytes(),
)
.expect_one()
{
success = false;
error!(
@@ -52,7 +53,7 @@ pub async fn validate_address_objects_0_12(
.await?
{
if let Err(err) =
ical_dev::parser::vcard::VcardParser::new(object.get_vcf().as_bytes())
ical_dev::parser::vcard::VcardParser::from_slice(object.get_vcf().as_bytes())
.expect_one()
{
success = false;