mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-14 21:42:26 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dabddc6282 | ||
|
|
76b4194b94 | ||
|
|
db144ebcae | ||
|
|
a53c333f1f | ||
|
|
a05baea472 | ||
|
|
f34f7e420e | ||
|
|
24ab323aa0 | ||
|
|
f34f56ca89 |
32
.sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json
generated
Normal file
32
.sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json
generated
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT id, uid, ics FROM calendarobjects\n WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL\n AND (last_occurence IS NULL OR ? IS NULL OR last_occurence >= date(?))\n AND (first_occurence IS NULL OR ? IS NULL OR first_occurence <= date(?))\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "uid",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ics",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 6
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39"
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "REPLACE INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, date(?), date(?), ?, ?)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 8
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "3e1cca532372e891ab3e604ecb79311d8cd64108d4f238db4c79e9467a3b6d2e"
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT id, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
"query": "SELECT id, uid, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -9,18 +9,24 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ics",
|
"name": "uid",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ics",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Right": 4
|
"Right": 4
|
||||||
},
|
},
|
||||||
"nullable": [
|
"nullable": [
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d"
|
"hash": "505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed"
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "INSERT INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, date(?), date(?), ?, ?)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 8
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "6327bee90e5df01536a0ddb15adcc37af3027f6902aa3786365c5ab2fbf06bda"
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT id, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
"query": "SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@@ -9,18 +9,24 @@
|
|||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ics",
|
"name": "uid",
|
||||||
"ordinal": 1,
|
"ordinal": 1,
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ics",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Right": 2
|
"Right": 2
|
||||||
},
|
},
|
||||||
"nullable": [
|
"nullable": [
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86"
|
"hash": "804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42"
|
||||||
}
|
}
|
||||||
12
.sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json
generated
Normal file
12
.sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "REPLACE INTO calendarobjects (principal, cal_id, id, uid, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, date(?), date(?), ?, ?)",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 9
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820"
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "SELECT id, ics FROM calendarobjects\n WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL\n AND (last_occurence IS NULL OR ? IS NULL OR last_occurence >= date(?))\n AND (first_occurence IS NULL OR ? IS NULL OR first_occurence <= date(?))\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "id",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ics",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 6
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "c550dbf3d5ce7069f28d767ea9045e477ef8d29d6186851760757a06dec42339"
|
|
||||||
}
|
|
||||||
12
.sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json
generated
Normal file
12
.sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "INSERT INTO calendarobjects (principal, cal_id, id, uid, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, date(?), date(?), ?, ?)",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 9
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556"
|
||||||
|
}
|
||||||
136
Cargo.lock
generated
136
Cargo.lock
generated
@@ -19,9 +19,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -397,13 +397,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-extra"
|
name = "axum-extra"
|
||||||
version = "0.10.3"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96"
|
checksum = "460c45604cb25834835e3b4d3468510322852783dac36261d642424d75562ff3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-core",
|
"axum-core",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"headers",
|
"headers",
|
||||||
"http",
|
"http",
|
||||||
@@ -411,8 +412,6 @@ dependencies = [
|
|||||||
"http-body-util",
|
"http-body-util",
|
||||||
"mime",
|
"mime",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustversion",
|
|
||||||
"serde_core",
|
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -532,9 +531,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.43"
|
version = "1.2.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2"
|
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
@@ -587,9 +586,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.50"
|
version = "4.5.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
|
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -597,9 +596,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.50"
|
version = "4.5.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
|
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -1582,9 +1581,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.0.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
|
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"potential_utf",
|
"potential_utf",
|
||||||
@@ -1595,9 +1594,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_locale_core"
|
name = "icu_locale_core"
|
||||||
version = "2.0.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
|
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"litemap",
|
"litemap",
|
||||||
@@ -1608,11 +1607,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer"
|
name = "icu_normalizer"
|
||||||
version = "2.0.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
|
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_normalizer_data",
|
"icu_normalizer_data",
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
@@ -1623,42 +1621,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer_data"
|
name = "icu_normalizer_data"
|
||||||
version = "2.0.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties"
|
name = "icu_properties"
|
||||||
version = "2.0.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
"icu_properties_data",
|
"icu_properties_data",
|
||||||
"icu_provider",
|
"icu_provider",
|
||||||
"potential_utf",
|
|
||||||
"zerotrie",
|
"zerotrie",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties_data"
|
name = "icu_properties_data"
|
||||||
version = "2.0.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_provider"
|
name = "icu_provider"
|
||||||
version = "2.0.0"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
|
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
"stable_deref_trait",
|
|
||||||
"tinystr",
|
|
||||||
"writeable",
|
"writeable",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@@ -1838,9 +1832,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -1963,11 +1957,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libm",
|
"libm",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
@@ -2476,9 +2469,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
|
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
@@ -2981,7 +2974,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical"
|
name = "rustical"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argon2",
|
"argon2",
|
||||||
@@ -3024,7 +3017,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_caldav"
|
name = "rustical_caldav"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3064,7 +3057,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_carddav"
|
name = "rustical_carddav"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -3096,7 +3089,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_dav"
|
name = "rustical_dav"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -3121,7 +3114,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_dav_push"
|
name = "rustical_dav_push"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -3146,7 +3139,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_frontend"
|
name = "rustical_frontend"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama",
|
"askama",
|
||||||
"askama_web",
|
"askama_web",
|
||||||
@@ -3179,7 +3172,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_ical"
|
name = "rustical_ical"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -3196,7 +3189,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_oidc"
|
name = "rustical_oidc"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -3212,7 +3205,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_store"
|
name = "rustical_store"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3245,7 +3238,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_store_sqlite"
|
name = "rustical_store_sqlite"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -3266,7 +3259,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustical_xml"
|
name = "rustical_xml"
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
@@ -3312,9 +3305,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.7"
|
version = "0.103.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
|
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -3999,9 +3992,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
|
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@@ -4456,24 +4449,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.20"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.24"
|
version = "0.1.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-properties"
|
name = "unicode-properties"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@@ -5011,9 +5004,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
version = "0.6.1"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml_derive"
|
name = "xml_derive"
|
||||||
@@ -5035,11 +5028,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
|
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"yoke-derive",
|
"yoke-derive",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@@ -5047,9 +5039,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke-derive"
|
name = "yoke-derive"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -5106,9 +5098,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
|
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"yoke",
|
"yoke",
|
||||||
@@ -5117,9 +5109,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.11.4"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
|
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@@ -5128,9 +5120,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec-derive"
|
name = "zerovec-derive"
|
||||||
version = "0.11.1"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.9.13"
|
version = "0.10.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A CalDAV server"
|
description = "A CalDAV server"
|
||||||
documentation = "https://lennart-k.github.io/rustical/"
|
documentation = "https://lennart-k.github.io/rustical/"
|
||||||
@@ -121,7 +121,7 @@ rustical_ical = { path = "./crates/ical/" }
|
|||||||
chrono-tz = "0.10"
|
chrono-tz = "0.10"
|
||||||
chrono-humanize = "0.2"
|
chrono-humanize = "0.2"
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
axum-extra = { version = "0.10", features = ["typed-header"] }
|
axum-extra = { version = "0.12", features = ["typed-header"] }
|
||||||
rrule = "0.14"
|
rrule = "0.14"
|
||||||
argon2 = "0.5"
|
argon2 = "0.5"
|
||||||
rpassword = "7.3"
|
rpassword = "7.3"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM --platform=$BUILDPLATFORM rust:1.90-alpine AS chef
|
FROM --platform=$BUILDPLATFORM rust:1.91-alpine AS chef
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
ARG BUILDPLATFORM
|
ARG BUILDPLATFORM
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ pub async fn route_import<C: CalendarStore, S: SubscriptionStore>(
|
|||||||
let objects = expanded_cals
|
let objects = expanded_cals
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|cal| cal.generate())
|
.map(|cal| cal.generate())
|
||||||
.map(CalendarObject::from_ics)
|
.map(|ics| CalendarObject::from_ics(ics, None))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let new_cal = Calendar {
|
let new_cal = Calendar {
|
||||||
principal,
|
principal,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rustical_ical::CalendarObject;
|
|||||||
use rustical_store::CalendarStore;
|
use rustical_store::CalendarStore;
|
||||||
use rustical_store::auth::Principal;
|
use rustical_store::auth::Principal;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tracing::{debug, error, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
#[instrument(skip(cal_store))]
|
#[instrument(skip(cal_store))]
|
||||||
pub async fn get_event<C: CalendarStore>(
|
pub async fn get_event<C: CalendarStore>(
|
||||||
@@ -78,18 +78,10 @@ pub async fn put_event<C: CalendarStore>(
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(object) = CalendarObject::from_ics(body.clone()) else {
|
let Ok(object) = CalendarObject::from_ics(body.clone(), Some(object_id)) else {
|
||||||
debug!("invalid calendar data:\n{body}");
|
debug!("invalid calendar data:\n{body}");
|
||||||
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
return Err(Error::PreconditionFailed(Precondition::ValidCalendarData));
|
||||||
};
|
};
|
||||||
if object.get_id() != object_id {
|
|
||||||
error!(
|
|
||||||
"Calendar object UID and file name not matching: UID={}, filename={}",
|
|
||||||
object.get_id(),
|
|
||||||
object_id
|
|
||||||
);
|
|
||||||
return Err(Error::PreconditionFailed(Precondition::MatchingUid));
|
|
||||||
}
|
|
||||||
cal_store
|
cal_store
|
||||||
.put_object(principal, calendar_id, object, overwrite)
|
.put_object(principal, calendar_id, object, overwrite)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ pub enum Precondition {
|
|||||||
#[error("valid-calendar-data")]
|
#[error("valid-calendar-data")]
|
||||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||||
ValidCalendarData,
|
ValidCalendarData,
|
||||||
#[error("matching-uid")]
|
|
||||||
MatchingUid,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for Precondition {
|
impl IntoResponse for Precondition {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ publish = false
|
|||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
tower.workspace = true
|
tower.workspace = true
|
||||||
axum-extra.workspace = true
|
axum-extra.workspace = true
|
||||||
|
|
||||||
rustical_xml.workspace = true
|
rustical_xml.workspace = true
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
futures-util.workspace = true
|
futures-util.workspace = true
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ impl<S: SubscriptionStore> DavPushController<S> {
|
|||||||
let mut latest_messages = HashMap::new();
|
let mut latest_messages = HashMap::new();
|
||||||
for message in messages {
|
for message in messages {
|
||||||
if matches!(message.data, CollectionOperationInfo::Content { .. }) {
|
if matches!(message.data, CollectionOperationInfo::Content { .. }) {
|
||||||
latest_messages.insert(message.topic.to_string(), message);
|
latest_messages.insert(message.topic.clone(), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let messages = latest_messages.into_values();
|
let messages = latest_messages.into_values();
|
||||||
@@ -156,12 +156,13 @@ impl<S: SubscriptionStore> DavPushController<S> {
|
|||||||
) -> Result<(), NotifierError> {
|
) -> Result<(), NotifierError> {
|
||||||
if subsciption.public_key_type != "p256dh" {
|
if subsciption.public_key_type != "p256dh" {
|
||||||
return Err(NotifierError::InvalidPublicKeyType(
|
return Err(NotifierError::InvalidPublicKeyType(
|
||||||
subsciption.public_key_type.to_string(),
|
subsciption.public_key_type.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let endpoint = subsciption.push_resource.parse().map_err(|_| {
|
let endpoint = subsciption
|
||||||
NotifierError::InvalidEndpointUrl(subsciption.push_resource.to_string())
|
.push_resource
|
||||||
})?;
|
.parse()
|
||||||
|
.map_err(|_| NotifierError::InvalidEndpointUrl(subsciption.push_resource.clone()))?;
|
||||||
let ua_public = base64::engine::general_purpose::URL_SAFE_NO_PAD
|
let ua_public = base64::engine::general_purpose::URL_SAFE_NO_PAD
|
||||||
.decode(&subsciption.public_key)
|
.decode(&subsciption.public_key)
|
||||||
.map_err(|_| NotifierError::InvalidKeyEncoding)?;
|
.map_err(|_| NotifierError::InvalidKeyEncoding)?;
|
||||||
|
|||||||
@@ -97,8 +97,9 @@ impl AddressObject {
|
|||||||
let uid = format!("{}-anniversary", self.get_id());
|
let uid = format!("{}-anniversary", self.get_id());
|
||||||
|
|
||||||
let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default();
|
let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default();
|
||||||
Some(CalendarObject::from_ics(format!(
|
Some(CalendarObject::from_ics(
|
||||||
r"BEGIN:VCALENDAR
|
format!(
|
||||||
|
r"BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
CALSCALE:GREGORIAN
|
CALSCALE:GREGORIAN
|
||||||
PRODID:-//github.com/lennart-k/rustical birthday calendar//EN
|
PRODID:-//github.com/lennart-k/rustical birthday calendar//EN
|
||||||
@@ -116,7 +117,9 @@ DESCRIPTION:💍 {fullname}{year_suffix}
|
|||||||
END:VALARM
|
END:VALARM
|
||||||
END:VEVENT
|
END:VEVENT
|
||||||
END:VCALENDAR",
|
END:VCALENDAR",
|
||||||
))?)
|
),
|
||||||
|
None,
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@@ -136,8 +139,9 @@ END:VCALENDAR",
|
|||||||
let uid = format!("{}-birthday", self.get_id());
|
let uid = format!("{}-birthday", self.get_id());
|
||||||
|
|
||||||
let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default();
|
let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default();
|
||||||
Some(CalendarObject::from_ics(format!(
|
Some(CalendarObject::from_ics(
|
||||||
r"BEGIN:VCALENDAR
|
format!(
|
||||||
|
r"BEGIN:VCALENDAR
|
||||||
VERSION:2.0
|
VERSION:2.0
|
||||||
CALSCALE:GREGORIAN
|
CALSCALE:GREGORIAN
|
||||||
PRODID:-//github.com/lennart-k/rustical birthday calendar//EN
|
PRODID:-//github.com/lennart-k/rustical birthday calendar//EN
|
||||||
@@ -155,7 +159,9 @@ DESCRIPTION:🎂 {fullname}{year_suffix}
|
|||||||
END:VALARM
|
END:VALARM
|
||||||
END:VEVENT
|
END:VEVENT
|
||||||
END:VCALENDAR",
|
END:VCALENDAR",
|
||||||
))?)
|
),
|
||||||
|
None,
|
||||||
|
)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ END:VEVENT\r\n",
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expand_recurrence() {
|
fn test_expand_recurrence() {
|
||||||
let event = CalendarObject::from_ics(ICS.to_string()).unwrap();
|
let event = CalendarObject::from_ics(ICS.to_string(), None).unwrap();
|
||||||
let crate::CalendarObjectComponent::Event(event, overrides) = event.get_data() else {
|
let crate::CalendarObjectComponent::Event(event, overrides) = event.get_data() else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,6 +64,19 @@ pub enum CalendarObjectComponent {
|
|||||||
Journal(IcalJournal, Vec<IcalJournal>),
|
Journal(IcalJournal, Vec<IcalJournal>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CalendarObjectComponent {
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_uid(&self) -> &str {
|
||||||
|
match &self {
|
||||||
|
// We've made sure before that the first component exists and all components share the
|
||||||
|
// same UID
|
||||||
|
Self::Todo(todo, _) => todo.get_uid(),
|
||||||
|
Self::Event(event, _) => event.event.get_uid(),
|
||||||
|
Self::Journal(journal, _) => journal.get_uid(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&CalendarObjectComponent> for CalendarObjectType {
|
impl From<&CalendarObjectComponent> for CalendarObjectType {
|
||||||
fn from(value: &CalendarObjectComponent) -> Self {
|
fn from(value: &CalendarObjectComponent) -> Self {
|
||||||
match value {
|
match value {
|
||||||
@@ -141,12 +154,13 @@ impl CalendarObjectComponent {
|
|||||||
pub struct CalendarObject {
|
pub struct CalendarObject {
|
||||||
data: CalendarObjectComponent,
|
data: CalendarObjectComponent,
|
||||||
properties: Vec<Property>,
|
properties: Vec<Property>,
|
||||||
|
id: String,
|
||||||
ics: String,
|
ics: String,
|
||||||
vtimezones: HashMap<String, IcalTimeZone>,
|
vtimezones: HashMap<String, IcalTimeZone>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CalendarObject {
|
impl CalendarObject {
|
||||||
pub fn from_ics(ics: String) -> Result<Self, Error> {
|
pub fn from_ics(ics: String, id: Option<String>) -> Result<Self, Error> {
|
||||||
let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes()));
|
let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes()));
|
||||||
let cal = parser.next().ok_or(Error::MissingCalendar)??;
|
let cal = parser.next().ok_or(Error::MissingCalendar)??;
|
||||||
if parser.next().is_some() {
|
if parser.next().is_some() {
|
||||||
@@ -202,6 +216,7 @@ impl CalendarObject {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
id: id.unwrap_or_else(|| data.get_uid().to_owned()),
|
||||||
data,
|
data,
|
||||||
properties: cal.properties,
|
properties: cal.properties,
|
||||||
ics,
|
ics,
|
||||||
@@ -219,21 +234,20 @@ impl CalendarObject {
|
|||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_uid(&self) -> &str {
|
||||||
|
self.data.get_uid()
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_id(&self) -> &str {
|
pub fn get_id(&self) -> &str {
|
||||||
match &self.data {
|
&self.id
|
||||||
// We've made sure before that the first component exists and all components share the
|
|
||||||
// same UID
|
|
||||||
CalendarObjectComponent::Todo(todo, _) => todo.get_uid(),
|
|
||||||
CalendarObjectComponent::Event(event, _) => event.event.get_uid(),
|
|
||||||
CalendarObjectComponent::Journal(journal, _) => journal.get_uid(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_etag(&self) -> String {
|
pub fn get_etag(&self) -> String {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(self.get_id());
|
hasher.update(self.get_uid());
|
||||||
hasher.update(self.get_ics());
|
hasher.update(self.get_ics());
|
||||||
format!("\"{:x}\"", hasher.finalize())
|
format!("\"{:x}\"", hasher.finalize())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ END:VCALENDAR
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_calendar_object() {
|
fn parse_calendar_object() {
|
||||||
let object = CalendarObject::from_ics(MULTI_VEVENT.to_string()).unwrap();
|
let object = CalendarObject::from_ics(MULTI_VEVENT.to_string(), None).unwrap();
|
||||||
object.expand_recurrence(None, None).unwrap();
|
object.expand_recurrence(None, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ reqwest.workspace = true
|
|||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
tower-sessions = "0.14"
|
tower-sessions.workspace = true
|
||||||
axum-extra.workspace = true
|
axum-extra.workspace = true
|
||||||
headers.workspace = true
|
headers.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use crate::synctoken::format_synctoken;
|
use crate::synctoken::format_synctoken;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use rustical_ical::CalendarObjectType;
|
use rustical_ical::CalendarObjectType;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct CalendarMetadata {
|
pub struct CalendarMetadata {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
DROP INDEX idx_calobjs_uid;
|
||||||
|
ALTER TABLE calendarobjects RENAME TO calendarobjects_old;
|
||||||
|
|
||||||
|
CREATE TABLE calendarobjects (
|
||||||
|
principal TEXT NOT NULL,
|
||||||
|
cal_id TEXT NOT NULL,
|
||||||
|
id TEXT NOT NULL, -- filename
|
||||||
|
ics TEXT NOT NULL,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at DATETIME,
|
||||||
|
|
||||||
|
-- For more efficient calendar-queries
|
||||||
|
first_occurence DATE,
|
||||||
|
last_occurence DATE,
|
||||||
|
etag TEXT,
|
||||||
|
object_type INTEGER NOT NULL, -- VEVENT(0)/VTODO(1)/VJOURNAL(2)
|
||||||
|
|
||||||
|
CONSTRAINT pk_calendarobject_id PRIMARY KEY (principal, cal_id, id),
|
||||||
|
CONSTRAINT fk_calendarobject_calendar FOREIGN KEY (principal, cal_id)
|
||||||
|
REFERENCES calendars (principal, id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO calendarobjects (
|
||||||
|
principal,
|
||||||
|
cal_id,
|
||||||
|
id,
|
||||||
|
ics,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
first_occurence,
|
||||||
|
last_occurence,
|
||||||
|
etag,
|
||||||
|
object_type
|
||||||
|
) SELECT
|
||||||
|
principal,
|
||||||
|
cal_id,
|
||||||
|
id,
|
||||||
|
ics,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
first_occurence,
|
||||||
|
last_occurence,
|
||||||
|
etag,
|
||||||
|
object_type
|
||||||
|
FROM calendarobjects_old;
|
||||||
|
|
||||||
|
DROP TABLE calendarobjects_old;
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
-- Adds the column "uid" and populates it with data from "id"
|
||||||
|
ALTER TABLE calendarobjects RENAME TO calendarobjects_old;
|
||||||
|
|
||||||
|
CREATE TABLE calendarobjects (
|
||||||
|
principal TEXT NOT NULL,
|
||||||
|
cal_id TEXT NOT NULL,
|
||||||
|
id TEXT NOT NULL, -- filename
|
||||||
|
"uid" TEXT NOT NULL, -- global identifier
|
||||||
|
ics TEXT NOT NULL,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
deleted_at DATETIME,
|
||||||
|
|
||||||
|
-- For more efficient calendar-queries
|
||||||
|
first_occurence DATE,
|
||||||
|
last_occurence DATE,
|
||||||
|
etag TEXT,
|
||||||
|
object_type INTEGER NOT NULL, -- VEVENT(0)/VTODO(1)/VJOURNAL(2)
|
||||||
|
|
||||||
|
CONSTRAINT pk_calendarobject_id PRIMARY KEY (principal, cal_id, id),
|
||||||
|
CONSTRAINT uq_calendarobject_uid UNIQUE (principal, cal_id, "uid"),
|
||||||
|
CONSTRAINT fk_calendarobject_calendar FOREIGN KEY (principal, cal_id)
|
||||||
|
REFERENCES calendars (principal, id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_calobjs_uid ON calendarobjects (principal, cal_id, "uid");
|
||||||
|
|
||||||
|
INSERT INTO calendarobjects (
|
||||||
|
principal,
|
||||||
|
cal_id,
|
||||||
|
id,
|
||||||
|
"uid",
|
||||||
|
ics,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
first_occurence,
|
||||||
|
last_occurence,
|
||||||
|
etag,
|
||||||
|
object_type
|
||||||
|
) SELECT
|
||||||
|
principal,
|
||||||
|
cal_id,
|
||||||
|
id,
|
||||||
|
id AS "uid",
|
||||||
|
ics,
|
||||||
|
updated_at,
|
||||||
|
deleted_at,
|
||||||
|
first_occurence,
|
||||||
|
last_occurence,
|
||||||
|
etag,
|
||||||
|
object_type
|
||||||
|
FROM calendarobjects_old;
|
||||||
|
|
||||||
|
DROP TABLE calendarobjects_old;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use super::ChangeOperation;
|
use super::ChangeOperation;
|
||||||
|
use crate::BEGIN_IMMEDIATE;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use derive_more::derive::Constructor;
|
use derive_more::derive::Constructor;
|
||||||
use rustical_ical::AddressObject;
|
use rustical_ical::AddressObject;
|
||||||
@@ -414,7 +415,11 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
addressbook_id: &str,
|
addressbook_id: &str,
|
||||||
use_trashbin: bool,
|
use_trashbin: bool,
|
||||||
) -> Result<(), rustical_store::Error> {
|
) -> Result<(), rustical_store::Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let addressbook =
|
let addressbook =
|
||||||
match Self::_get_addressbook(&mut *tx, principal, addressbook_id, use_trashbin).await {
|
match Self::_get_addressbook(&mut *tx, principal, addressbook_id, use_trashbin).await {
|
||||||
@@ -508,7 +513,11 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
object: AddressObject,
|
object: AddressObject,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), rustical_store::Error> {
|
) -> Result<(), rustical_store::Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let object_id = object.get_id().to_owned();
|
let object_id = object.get_id().to_owned();
|
||||||
|
|
||||||
@@ -554,7 +563,11 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
object_id: &str,
|
object_id: &str,
|
||||||
use_trashbin: bool,
|
use_trashbin: bool,
|
||||||
) -> Result<(), rustical_store::Error> {
|
) -> Result<(), rustical_store::Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
Self::_delete_object(&mut *tx, principal, addressbook_id, object_id, use_trashbin).await?;
|
Self::_delete_object(&mut *tx, principal, addressbook_id, object_id, use_trashbin).await?;
|
||||||
|
|
||||||
@@ -589,7 +602,11 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
addressbook_id: &str,
|
addressbook_id: &str,
|
||||||
object_id: &str,
|
object_id: &str,
|
||||||
) -> Result<(), rustical_store::Error> {
|
) -> Result<(), rustical_store::Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
Self::_restore_object(&mut *tx, principal, addressbook_id, object_id).await?;
|
Self::_restore_object(&mut *tx, principal, addressbook_id, object_id).await?;
|
||||||
|
|
||||||
@@ -624,7 +641,11 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
objects: Vec<AddressObject>,
|
objects: Vec<AddressObject>,
|
||||||
merge_existing: bool,
|
merge_existing: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let existing =
|
let existing =
|
||||||
match Self::_get_addressbook(&mut *tx, &addressbook.principal, &addressbook.id, true)
|
match Self::_get_addressbook(&mut *tx, &addressbook.principal, &addressbook.id, true)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use super::ChangeOperation;
|
use super::ChangeOperation;
|
||||||
|
use crate::BEGIN_IMMEDIATE;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::TimeDelta;
|
use chrono::TimeDelta;
|
||||||
use derive_more::derive::Constructor;
|
use derive_more::derive::Constructor;
|
||||||
@@ -16,19 +17,20 @@ use tracing::{error, instrument};
|
|||||||
struct CalendarObjectRow {
|
struct CalendarObjectRow {
|
||||||
id: String,
|
id: String,
|
||||||
ics: String,
|
ics: String,
|
||||||
|
uid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<CalendarObjectRow> for CalendarObject {
|
impl TryFrom<CalendarObjectRow> for CalendarObject {
|
||||||
type Error = rustical_store::Error;
|
type Error = rustical_store::Error;
|
||||||
|
|
||||||
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
fn try_from(value: CalendarObjectRow) -> Result<Self, Self::Error> {
|
||||||
let object = Self::from_ics(value.ics)?;
|
let object = Self::from_ics(value.ics, Some(value.id))?;
|
||||||
if object.get_id() != value.id {
|
if object.get_uid() != value.uid {
|
||||||
return Err(rustical_store::Error::IcalError(
|
return Err(rustical_store::Error::IcalError(
|
||||||
rustical_ical::Error::InvalidData(format!(
|
rustical_ical::Error::InvalidData(format!(
|
||||||
"object_id={} and UID={} don't match",
|
"uid={} and UID={} don't match",
|
||||||
object.get_id(),
|
value.uid,
|
||||||
value.id
|
object.get_uid()
|
||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -280,7 +282,7 @@ impl SqliteCalendarStore {
|
|||||||
) -> Result<Vec<CalendarObject>, Error> {
|
) -> Result<Vec<CalendarObject>, Error> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
CalendarObjectRow,
|
CalendarObjectRow,
|
||||||
"SELECT id, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
"SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL",
|
||||||
principal,
|
principal,
|
||||||
cal_id
|
cal_id
|
||||||
)
|
)
|
||||||
@@ -305,7 +307,7 @@ impl SqliteCalendarStore {
|
|||||||
|
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
CalendarObjectRow,
|
CalendarObjectRow,
|
||||||
r"SELECT id, ics FROM calendarobjects
|
r"SELECT id, uid, ics FROM calendarobjects
|
||||||
WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL
|
WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL
|
||||||
AND (last_occurence IS NULL OR ? IS NULL OR last_occurence >= date(?))
|
AND (last_occurence IS NULL OR ? IS NULL OR last_occurence >= date(?))
|
||||||
AND (first_occurence IS NULL OR ? IS NULL OR first_occurence <= date(?))
|
AND (first_occurence IS NULL OR ? IS NULL OR first_occurence <= date(?))
|
||||||
@@ -334,7 +336,7 @@ impl SqliteCalendarStore {
|
|||||||
) -> Result<CalendarObject, Error> {
|
) -> Result<CalendarObject, Error> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
CalendarObjectRow,
|
CalendarObjectRow,
|
||||||
"SELECT id, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
"SELECT id, uid, ics FROM calendarobjects WHERE (principal, cal_id, id) = (?, ?, ?) AND ((deleted_at IS NULL) OR ?)",
|
||||||
principal,
|
principal,
|
||||||
cal_id,
|
cal_id,
|
||||||
object_id,
|
object_id,
|
||||||
@@ -354,7 +356,7 @@ impl SqliteCalendarStore {
|
|||||||
object: CalendarObject,
|
object: CalendarObject,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let (object_id, ics) = (object.get_id(), object.get_ics());
|
let (object_id, uid, ics) = (object.get_id(), object.get_uid(), object.get_ics());
|
||||||
|
|
||||||
let first_occurence = object
|
let first_occurence = object
|
||||||
.get_first_occurence()
|
.get_first_occurence()
|
||||||
@@ -373,10 +375,11 @@ impl SqliteCalendarStore {
|
|||||||
|
|
||||||
(if overwrite {
|
(if overwrite {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"REPLACE INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, date(?), date(?), ?, ?)",
|
"REPLACE INTO calendarobjects (principal, cal_id, id, uid, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, date(?), date(?), ?, ?)",
|
||||||
principal,
|
principal,
|
||||||
cal_id,
|
cal_id,
|
||||||
object_id,
|
object_id,
|
||||||
|
uid,
|
||||||
ics,
|
ics,
|
||||||
first_occurence,
|
first_occurence,
|
||||||
last_occurence,
|
last_occurence,
|
||||||
@@ -386,10 +389,11 @@ impl SqliteCalendarStore {
|
|||||||
} else {
|
} else {
|
||||||
// If the object already exists a database error is thrown and handled in error.rs
|
// If the object already exists a database error is thrown and handled in error.rs
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO calendarobjects (principal, cal_id, id, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, date(?), date(?), ?, ?)",
|
"INSERT INTO calendarobjects (principal, cal_id, id, uid, ics, first_occurence, last_occurence, etag, object_type) VALUES (?, ?, ?, ?, ?, date(?), date(?), ?, ?)",
|
||||||
principal,
|
principal,
|
||||||
cal_id,
|
cal_id,
|
||||||
object_id,
|
object_id,
|
||||||
|
uid,
|
||||||
ics,
|
ics,
|
||||||
first_occurence,
|
first_occurence,
|
||||||
last_occurence,
|
last_occurence,
|
||||||
@@ -409,7 +413,7 @@ impl SqliteCalendarStore {
|
|||||||
executor: E,
|
executor: E,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
id: &str,
|
object_id: &str,
|
||||||
use_trashbin: bool,
|
use_trashbin: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if use_trashbin {
|
if use_trashbin {
|
||||||
@@ -417,7 +421,7 @@ impl SqliteCalendarStore {
|
|||||||
"UPDATE calendarobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)",
|
"UPDATE calendarobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)",
|
||||||
principal,
|
principal,
|
||||||
cal_id,
|
cal_id,
|
||||||
id
|
object_id
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await.map_err(crate::Error::from)?;
|
.await.map_err(crate::Error::from)?;
|
||||||
@@ -425,7 +429,7 @@ impl SqliteCalendarStore {
|
|||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"DELETE FROM calendarobjects WHERE cal_id = ? AND id = ?",
|
"DELETE FROM calendarobjects WHERE cal_id = ? AND id = ?",
|
||||||
cal_id,
|
cal_id,
|
||||||
id
|
object_id
|
||||||
)
|
)
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await
|
.await
|
||||||
@@ -539,7 +543,11 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
id: &str,
|
id: &str,
|
||||||
use_trashbin: bool,
|
use_trashbin: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let cal = match Self::_get_calendar(&mut *tx, principal, id, true).await {
|
let cal = match Self::_get_calendar(&mut *tx, principal, id, true).await {
|
||||||
Ok(cal) => Some(cal),
|
Ok(cal) => Some(cal),
|
||||||
@@ -573,7 +581,11 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
objects: Vec<CalendarObject>,
|
objects: Vec<CalendarObject>,
|
||||||
merge_existing: bool,
|
merge_existing: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let existing_cal =
|
let existing_cal =
|
||||||
match Self::_get_calendar(&mut *tx, &calendar.principal, &calendar.id, true).await {
|
match Self::_get_calendar(&mut *tx, &calendar.principal, &calendar.id, true).await {
|
||||||
@@ -663,7 +675,11 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
object: CalendarObject,
|
object: CalendarObject,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let object_id = object.get_id().to_owned();
|
let object_id = object.get_id().to_owned();
|
||||||
|
|
||||||
@@ -713,7 +729,11 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
id: &str,
|
id: &str,
|
||||||
use_trashbin: bool,
|
use_trashbin: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
Self::_delete_object(&mut *tx, principal, cal_id, id, use_trashbin).await?;
|
Self::_delete_object(&mut *tx, principal, cal_id, id, use_trashbin).await?;
|
||||||
|
|
||||||
@@ -737,7 +757,11 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
cal_id: &str,
|
cal_id: &str,
|
||||||
object_id: &str,
|
object_id: &str,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
|
let mut tx = self
|
||||||
|
.db
|
||||||
|
.begin_with(BEGIN_IMMEDIATE)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
Self::_restore_object(&mut *tx, principal, cal_id, object_id).await?;
|
Self::_restore_object(&mut *tx, principal, cal_id, object_id).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ pub mod error;
|
|||||||
pub mod principal_store;
|
pub mod principal_store;
|
||||||
pub mod subscription_store;
|
pub mod subscription_store;
|
||||||
|
|
||||||
|
// Begin statement for write transactions
|
||||||
|
pub const BEGIN_IMMEDIATE: &str = "BEGIN IMMEDIATE";
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test"))]
|
#[cfg(any(test, feature = "test"))]
|
||||||
pub mod tests;
|
pub mod tests;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user