From 08041c60be42d88bb8243c06f26f358b7f98adb4 Mon Sep 17 00:00:00 2001 From: Lennart K <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:39:24 +0100 Subject: [PATCH 01/15] clippy: Enable more warnings --- crates/caldav/src/lib.rs | 1 + crates/carddav/src/lib.rs | 1 + crates/dav/src/lib.rs | 1 + crates/dav_push/src/lib.rs | 1 + crates/frontend/src/lib.rs | 1 + crates/ical/src/lib.rs | 1 + crates/oidc/src/lib.rs | 1 + crates/store/src/lib.rs | 1 + crates/store_sqlite/src/lib.rs | 1 + crates/xml/src/lib.rs | 1 + src/main.rs | 1 + 11 files changed, 11 insertions(+) diff --git a/crates/caldav/src/lib.rs b/crates/caldav/src/lib.rs index 72e5071..d527551 100644 --- a/crates/caldav/src/lib.rs +++ b/crates/caldav/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use axum::{Extension, Router}; use derive_more::Constructor; use principal::PrincipalResourceService; diff --git a/crates/carddav/src/lib.rs b/crates/carddav/src/lib.rs index 1cb8f54..ce87be6 100644 --- a/crates/carddav/src/lib.rs +++ b/crates/carddav/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use axum::response::Redirect; use axum::routing::any; use axum::{Extension, Router}; diff --git a/crates/dav/src/lib.rs b/crates/dav/src/lib.rs index e23d682..3d2c179 100644 --- a/crates/dav/src/lib.rs +++ b/crates/dav/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] pub mod error; pub mod extensions; pub mod header; diff --git a/crates/dav_push/src/lib.rs b/crates/dav_push/src/lib.rs index e27b394..835c530 100644 --- a/crates/dav_push/src/lib.rs +++ b/crates/dav_push/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] mod extension; mod prop; pub mod register; diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index 8486500..c16a58d 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use axum::{ Extension, RequestExt, Router, body::Body, diff --git a/crates/ical/src/lib.rs b/crates/ical/src/lib.rs index 623c088..a02d1c8 100644 --- a/crates/ical/src/lib.rs +++ b/crates/ical/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] mod timestamp; mod timezone; pub use timestamp::*; diff --git a/crates/oidc/src/lib.rs b/crates/oidc/src/lib.rs index 0299fd4..b86b463 100644 --- a/crates/oidc/src/lib.rs +++ b/crates/oidc/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use axum::{ Extension, Form, extract::Query, diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index fb95fec..73ac4d2 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] pub mod addressbook; pub mod addressbook_store; pub mod calendar_store; diff --git a/crates/store_sqlite/src/lib.rs b/crates/store_sqlite/src/lib.rs index 3a911ac..eb0e0c6 100644 --- a/crates/store_sqlite/src/lib.rs +++ b/crates/store_sqlite/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] pub use error::Error; use serde::Serialize; use sqlx::{Pool, Sqlite, SqlitePool, sqlite::SqliteConnectOptions}; diff --git a/crates/xml/src/lib.rs b/crates/xml/src/lib.rs index b28737a..271efc8 100644 --- a/crates/xml/src/lib.rs +++ b/crates/xml/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use quick_xml::name::Namespace; use std::collections::HashMap; use std::hash::Hash; diff --git a/src/main.rs b/src/main.rs index b5b3a4d..ace4304 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] use crate::config::Config; use anyhow::Result; use app::make_app; From 0d071d3b926a6b1015d42e10eabdf467fba77b1b Mon Sep 17 00:00:00 2001 From: Lennart K <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:01:04 +0100 Subject: [PATCH 02/15] run clippy fix --- crates/caldav/src/calendar/methods/import.rs | 6 +- .../caldav/src/calendar/methods/mkcalendar.rs | 8 +- crates/caldav/src/calendar/methods/post.rs | 5 +- .../methods/report/calendar_multiget.rs | 8 +- .../methods/report/calendar_query/elements.rs | 29 +++-- .../methods/report/calendar_query/mod.rs | 2 +- .../caldav/src/calendar/methods/report/mod.rs | 8 +- crates/caldav/src/calendar/prop.rs | 10 +- crates/caldav/src/calendar/resource.rs | 8 +- crates/caldav/src/calendar/service.rs | 2 +- crates/caldav/src/calendar_object/methods.rs | 9 +- crates/caldav/src/calendar_object/prop.rs | 4 +- crates/caldav/src/calendar_object/resource.rs | 2 +- crates/caldav/src/calendar_object/service.rs | 2 +- crates/caldav/src/error.rs | 20 ++-- crates/caldav/src/lib.rs | 4 +- crates/caldav/src/principal/mod.rs | 4 +- crates/caldav/src/principal/prop.rs | 6 +- crates/carddav/src/address_object/prop.rs | 2 +- .../carddav/src/addressbook/methods/mkcol.rs | 14 +-- .../carddav/src/addressbook/methods/post.rs | 5 +- .../methods/report/addressbook_multiget.rs | 6 +- .../src/addressbook/methods/report/mod.rs | 6 +- crates/carddav/src/addressbook/prop.rs | 6 +- crates/carddav/src/addressbook/resource.rs | 6 +- crates/carddav/src/addressbook/service.rs | 2 +- crates/carddav/src/error.rs | 16 +-- crates/carddav/src/lib.rs | 6 +- crates/carddav/src/principal/mod.rs | 2 +- crates/carddav/src/principal/prop.rs | 4 +- crates/carddav/src/principal/service.rs | 2 +- crates/dav/src/error.rs | 8 +- crates/dav/src/extensions/common.rs | 2 +- crates/dav/src/extensions/synctoken.rs | 2 +- crates/dav/src/header/depth.rs | 14 +-- crates/dav/src/header/overwrite.rs | 2 +- crates/dav/src/privileges.rs | 16 +-- crates/dav/src/resource/axum_methods.rs | 16 +-- crates/dav/src/resource/axum_service.rs | 4 +- crates/dav/src/resource/methods/copy.rs | 2 +- crates/dav/src/resource/methods/delete.rs | 5 +- crates/dav/src/resource/methods/mod.rs | 10 +- crates/dav/src/resource/methods/mv.rs | 2 +- crates/dav/src/resource/methods/propfind.rs | 4 +- crates/dav/src/resource/methods/proppatch.rs | 12 +- crates/dav/src/resource/mod.rs | 12 +- crates/dav/src/resources/root.rs | 4 +- crates/dav/src/xml/group.rs | 4 +- crates/dav/src/xml/href.rs | 4 +- crates/dav/src/xml/multistatus.rs | 4 +- crates/dav/src/xml/propfind.rs | 4 +- crates/dav/src/xml/report_set.rs | 6 +- crates/dav/src/xml/resourcetype.rs | 4 +- crates/dav/src/xml/sync_collection.rs | 10 +- crates/dav/src/xml/tag_list.rs | 11 +- crates/dav_push/src/lib.rs | 4 +- crates/dav_push/src/prop.rs | 6 +- crates/dav_push/src/register.rs | 2 +- crates/frontend/src/config.rs | 2 +- crates/frontend/src/lib.rs | 10 +- crates/frontend/src/nextcloud_login/mod.rs | 2 +- crates/frontend/src/nextcloud_login/routes.rs | 26 ++--- crates/frontend/src/routes/app_token.rs | 6 +- crates/ical/src/address_object.rs | 20 ++-- crates/ical/src/error.rs | 2 +- crates/ical/src/icalendar/event.rs | 8 +- crates/ical/src/icalendar/object.rs | 40 +++---- crates/ical/src/timestamp.rs | 103 +++++++++--------- crates/ical/src/timezone.rs | 2 +- crates/oidc/src/lib.rs | 2 +- crates/store/src/addressbook.rs | 2 +- crates/store/src/auth/middleware.rs | 2 +- crates/store/src/auth/principal.rs | 2 +- crates/store/src/auth/principal_type.rs | 16 +-- crates/store/src/calendar.rs | 8 +- crates/store/src/contact_birthday_store.rs | 6 +- crates/store/src/error.rs | 2 +- crates/store/src/synctoken.rs | 4 +- crates/store_sqlite/src/addressbook_store.rs | 99 ++++++++--------- crates/store_sqlite/src/calendar_store.rs | 99 ++++++++--------- crates/store_sqlite/src/error.rs | 8 +- crates/store_sqlite/src/lib.rs | 2 +- crates/store_sqlite/src/principal_store.rs | 2 +- crates/xml/src/de.rs | 6 +- crates/xml/src/namespace.rs | 4 +- crates/xml/src/se.rs | 9 +- crates/xml/src/unparsed.rs | 4 +- crates/xml/src/value.rs | 13 +-- src/app.rs | 19 ++-- src/commands/membership.rs | 6 +- src/commands/mod.rs | 5 +- src/commands/principals.rs | 4 +- src/config.rs | 2 +- src/main.rs | 4 +- 94 files changed, 455 insertions(+), 484 deletions(-) diff --git a/crates/caldav/src/calendar/methods/import.rs b/crates/caldav/src/calendar/methods/import.rs index 8cadeb6..4a82cb2 100644 --- a/crates/caldav/src/calendar/methods/import.rs +++ b/crates/caldav/src/calendar/methods/import.rs @@ -45,13 +45,13 @@ pub async fn route_import( // Extract calendar metadata let displayname = cal .get_property("X-WR-CALNAME") - .and_then(|prop| prop.value.to_owned()); + .and_then(|prop| prop.value.clone()); let description = cal .get_property("X-WR-CALDESC") - .and_then(|prop| prop.value.to_owned()); + .and_then(|prop| prop.value.clone()); let timezone_id = cal .get_property("X-WR-TIMEZONE") - .and_then(|prop| prop.value.to_owned()); + .and_then(|prop| prop.value.clone()); // These properties should not appear in the expanded calendar objects cal.remove_property("X-WR-CALNAME"); cal.remove_property("X-WR-CALDESC"); diff --git a/crates/caldav/src/calendar/methods/mkcalendar.rs b/crates/caldav/src/calendar/methods/mkcalendar.rs index 6381c5d..0ec65c9 100644 --- a/crates/caldav/src/calendar/methods/mkcalendar.rs +++ b/crates/caldav/src/calendar/methods/mkcalendar.rs @@ -79,8 +79,8 @@ pub async fn route_mkcalendar( _ => unreachable!("We never call with another method"), }; - if let Some("") = request.displayname.as_deref() { - request.displayname = None + if request.displayname.as_deref() == Some("") { + request.displayname = None; } let timezone_id = if let Some(tzid) = request.calendar_timezone_id { @@ -110,8 +110,8 @@ pub async fn route_mkcalendar( }; let calendar = Calendar { - id: cal_id.to_owned(), - principal: principal.to_owned(), + id: cal_id.clone(), + principal: principal.clone(), meta: CalendarMetadata { order: request.calendar_order.unwrap_or(0), displayname: request.displayname, diff --git a/crates/caldav/src/calendar/methods/post.rs b/crates/caldav/src/calendar/methods/post.rs index f246ea2..014d10a 100644 --- a/crates/caldav/src/calendar/methods/post.rs +++ b/crates/caldav/src/calendar/methods/post.rs @@ -49,12 +49,11 @@ pub async fn route_post( }; let subscription = Subscription { - id: sub_id.to_owned(), + id: sub_id.clone(), push_resource: request .subscription .web_push_subscription - .push_resource - .to_owned(), + .push_resource.clone(), topic: calendar_resource.cal.push_topic, expiration: expires.naive_local(), public_key: request diff --git a/crates/caldav/src/calendar/methods/report/calendar_multiget.rs b/crates/caldav/src/calendar/methods/report/calendar_multiget.rs index e8b2d43..dd5af84 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_multiget.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_multiget.rs @@ -4,10 +4,10 @@ use rustical_ical::CalendarObject; use rustical_store::CalendarStore; use rustical_xml::XmlDeserialize; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] // -pub(crate) struct CalendarMultigetRequest { +pub struct CalendarMultigetRequest { #[xml(ty = "untagged")] pub(crate) prop: PropfindType, #[xml(flatten)] @@ -27,13 +27,13 @@ pub async fn get_objects_calendar_multiget( for href in &cal_query.href { if let Some(filename) = href.strip_prefix(path) { - let filename = filename.trim_start_matches("/"); + let filename = filename.trim_start_matches('/'); if let Some(object_id) = filename.strip_suffix(".ics") { match store.get_object(principal, cal_id, object_id, false).await { Ok(object) => result.push(object), Err(rustical_store::Error::NotFound) => not_found.push(href.to_owned()), Err(err) => return Err(err.into()), - }; + } } else { not_found.push(href.to_owned()); continue; diff --git a/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs b/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs index edfa64e..64ce9c4 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs @@ -3,18 +3,17 @@ use rustical_dav::xml::PropfindType; use rustical_ical::{CalendarObject, UtcDateTime}; use rustical_store::calendar_store::CalendarQuery; use rustical_xml::XmlDeserialize; -use std::ops::Deref; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] -pub(crate) struct TimeRangeElement { +pub struct TimeRangeElement { #[xml(ty = "attr")] pub(crate) start: Option, #[xml(ty = "attr")] pub(crate) end: Option, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] // https://www.rfc-editor.org/rfc/rfc4791#section-9.7.3 pub struct ParamFilterElement { @@ -27,7 +26,7 @@ pub struct ParamFilterElement { pub(crate) name: String, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] pub struct TextMatchElement { #[xml(ty = "attr")] @@ -40,7 +39,7 @@ pub struct TextMatchElement { #[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[allow(dead_code)] // https://www.rfc-editor.org/rfc/rfc4791#section-9.7.2 -pub(crate) struct PropFilterElement { +pub struct PropFilterElement { #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] pub(crate) is_not_defined: Option<()>, #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] @@ -57,7 +56,7 @@ pub(crate) struct PropFilterElement { #[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[allow(dead_code)] // https://datatracker.ietf.org/doc/html/rfc4791#section-9.7.1 -pub(crate) struct CompFilterElement { +pub struct CompFilterElement { #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] pub(crate) is_not_defined: Option<()>, #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] @@ -81,7 +80,7 @@ impl CompFilterElement { // Client is asking for something different than a vcalendar (None, false) => return false, _ => {} - }; + } if self.time_range.is_some() { // should be applied on VEVENT/VTODO but not on VCALENDAR @@ -111,20 +110,20 @@ impl CompFilterElement { // Client is asking for something different than a vcalendar (None, false) => return false, _ => {} - }; + } // TODO: Implement prop-filter (and comp-filter?) at some point if let Some(time_range) = &self.time_range { if let Some(start) = &time_range.start && let Some(last_occurence) = cal_object.get_last_occurence().unwrap_or(None) - && start.deref() > &last_occurence.utc() + && **start > last_occurence.utc() { return false; } if let Some(end) = &time_range.end && let Some(first_occurence) = cal_object.get_first_occurence().unwrap_or(None) - && end.deref() < &first_occurence.utc() + && **end < first_occurence.utc() { return false; } @@ -136,7 +135,7 @@ impl CompFilterElement { #[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[allow(dead_code)] // https://datatracker.ietf.org/doc/html/rfc4791#section-9.7 -pub(crate) struct FilterElement { +pub struct FilterElement { // This comp-filter matches on VCALENDAR #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] pub(crate) comp_filter: CompFilterElement, @@ -151,7 +150,7 @@ impl FilterElement { impl From<&FilterElement> for CalendarQuery { fn from(value: &FilterElement) -> Self { let comp_filter_vcalendar = &value.comp_filter; - for comp_filter in comp_filter_vcalendar.comp_filter.iter() { + for comp_filter in &comp_filter_vcalendar.comp_filter { // A calendar object cannot contain both VEVENT and VTODO, so we only have to handle // whatever we get first if matches!(comp_filter.name.as_str(), "VEVENT" | "VTODO") @@ -159,7 +158,7 @@ impl From<&FilterElement> for CalendarQuery { { let start = time_range.start.as_ref().map(|start| start.date_naive()); let end = time_range.end.as_ref().map(|end| end.date_naive()); - return CalendarQuery { + return Self { time_start: start, time_end: end, }; @@ -188,7 +187,7 @@ impl From<&CalendarQueryRequest> for CalendarQuery { value .filter .as_ref() - .map(CalendarQuery::from) + .map(Self::from) .unwrap_or_default() } } diff --git a/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs b/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs index 302f33d..34d4835 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs @@ -3,7 +3,7 @@ use rustical_ical::CalendarObject; use rustical_store::CalendarStore; mod elements; -pub(crate) use elements::*; +pub use elements::*; pub async fn get_objects_calendar_query( cal_query: &CalendarQueryRequest, diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs index 9af5cba..5952aea 100644 --- a/crates/caldav/src/calendar/methods/report/mod.rs +++ b/crates/caldav/src/calendar/methods/report/mod.rs @@ -41,11 +41,11 @@ pub(crate) enum ReportRequest { } impl ReportRequest { - fn props(&self) -> &PropfindType { + const fn props(&self) -> &PropfindType { match &self { - ReportRequest::CalendarMultiget(CalendarMultigetRequest { prop, .. }) => prop, - ReportRequest::CalendarQuery(CalendarQueryRequest { prop, .. }) => prop, - ReportRequest::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, + Self::CalendarMultiget(CalendarMultigetRequest { prop, .. }) => prop, + Self::CalendarQuery(CalendarQueryRequest { prop, .. }) => prop, + Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, } } } diff --git a/crates/caldav/src/calendar/prop.rs b/crates/caldav/src/calendar/prop.rs index e16e658..fa74bf6 100644 --- a/crates/caldav/src/calendar/prop.rs +++ b/crates/caldav/src/calendar/prop.rs @@ -3,13 +3,13 @@ use rustical_ical::CalendarObjectType; use rustical_xml::{XmlDeserialize, XmlSerialize}; use strum_macros::VariantArray; -#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq, From, Into)] +#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq, Eq, From, Into)] pub struct SupportedCalendarComponent { #[xml(ty = "attr")] pub name: CalendarObjectType, } -#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, PartialEq, Eq)] pub struct SupportedCalendarComponentSet { #[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)] pub comp: Vec, @@ -36,7 +36,7 @@ impl From for Vec { } } -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct CalendarData { #[xml(ty = "attr")] content_type: String, @@ -53,13 +53,13 @@ impl Default for CalendarData { } } -#[derive(Debug, Clone, XmlSerialize, Default, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, Default, PartialEq, Eq)] pub struct SupportedCalendarData { #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] calendar_data: CalendarData, } -#[derive(Debug, Clone, XmlSerialize, PartialEq, VariantArray)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq, VariantArray)] pub enum ReportMethod { #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] CalendarQuery, diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 1f36a69..785ca77 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -71,7 +71,7 @@ pub struct CalendarResource { impl ResourceName for CalendarResource { fn get_name(&self) -> String { - self.cal.id.to_owned() + self.cal.id.clone() } } @@ -89,7 +89,7 @@ impl SyncTokenExtension for CalendarResource { impl DavPushExtension for CalendarResource { fn get_topic(&self) -> String { - self.cal.push_topic.to_owned() + self.cal.push_topic.clone() } } @@ -135,7 +135,7 @@ impl Resource for CalendarResource { } CalendarPropName::CalendarTimezone => { CalendarProp::CalendarTimezone(self.cal.timezone_id.as_ref().and_then(|tzid| { - vtimezones_rs::VTIMEZONES.get(tzid).map(|tz| tz.to_string()) + vtimezones_rs::VTIMEZONES.get(tzid).map(|tz| (*tz).to_string()) })) } // chrono_tz uses the IANA database @@ -159,7 +159,7 @@ impl Resource for CalendarResource { CalendarProp::SupportedReportSet(SupportedReportSet::all()) } CalendarPropName::Source => CalendarProp::Source( - self.cal.subscription_url.to_owned().map(HrefElement::from), + self.cal.subscription_url.clone().map(HrefElement::from), ), CalendarPropName::MinDateTime => { CalendarProp::MinDateTime(CalDateTime::from(DateTime::::MIN_UTC).format()) diff --git a/crates/caldav/src/calendar/service.rs b/crates/caldav/src/calendar/service.rs index b9c2396..ec6384d 100644 --- a/crates/caldav/src/calendar/service.rs +++ b/crates/caldav/src/calendar/service.rs @@ -35,7 +35,7 @@ impl Clone for CalendarResourceService CalendarResourceService { - pub fn new(cal_store: Arc, sub_store: Arc) -> Self { + pub const fn new(cal_store: Arc, sub_store: Arc) -> Self { Self { cal_store, sub_store, diff --git a/crates/caldav/src/calendar_object/methods.rs b/crates/caldav/src/calendar_object/methods.rs index 2496ee0..1053076 100644 --- a/crates/caldav/src/calendar_object/methods.rs +++ b/crates/caldav/src/calendar_object/methods.rs @@ -78,12 +78,9 @@ pub async fn put_event( true }; - let object = match CalendarObject::from_ics(body.clone()) { - Ok(obj) => obj, - Err(_) => { - debug!("invalid calendar data:\n{body}"); - return Err(Error::PreconditionFailed(Precondition::ValidCalendarData)); - } + let object = if let Ok(obj) = CalendarObject::from_ics(body.clone()) { obj } else { + debug!("invalid calendar data:\n{body}"); + return Err(Error::PreconditionFailed(Precondition::ValidCalendarData)); }; if object.get_id() != object_id { error!( diff --git a/crates/caldav/src/calendar_object/prop.rs b/crates/caldav/src/calendar_object/prop.rs index ebd181d..0922e6d 100644 --- a/crates/caldav/src/calendar_object/prop.rs +++ b/crates/caldav/src/calendar_object/prop.rs @@ -2,7 +2,7 @@ use rustical_dav::extensions::CommonPropertiesProp; use rustical_ical::UtcDateTime; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "CalendarObjectPropName")] pub enum CalendarObjectProp { // WebDAV (RFC 2518) @@ -25,7 +25,7 @@ pub enum CalendarObjectPropWrapper { } #[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) struct ExpandElement { +pub struct ExpandElement { #[xml(ty = "attr")] pub(crate) start: UtcDateTime, #[xml(ty = "attr")] diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index b58cec6..cd3690f 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -1,4 +1,4 @@ -use super::prop::*; +use super::prop::{CalendarObjectPropWrapper, CalendarObjectPropWrapperName, CalendarObjectPropName, CalendarObjectProp, CalendarData}; use crate::Error; use derive_more::derive::{From, Into}; use rustical_dav::{ diff --git a/crates/caldav/src/calendar_object/service.rs b/crates/caldav/src/calendar_object/service.rs index 11625ba..f6527c8 100644 --- a/crates/caldav/src/calendar_object/service.rs +++ b/crates/caldav/src/calendar_object/service.rs @@ -35,7 +35,7 @@ impl Clone for CalendarObjectResourceService { } impl CalendarObjectResourceService { - pub fn new(cal_store: Arc) -> Self { + pub const fn new(cal_store: Arc) -> Self { Self { cal_store } } } diff --git a/crates/caldav/src/error.rs b/crates/caldav/src/error.rs index 7273007..a3a56c5 100644 --- a/crates/caldav/src/error.rs +++ b/crates/caldav/src/error.rs @@ -62,23 +62,23 @@ pub enum Error { } impl Error { - pub fn status_code(&self) -> StatusCode { + #[must_use] pub fn status_code(&self) -> StatusCode { match self { - Error::StoreError(err) => match err { + Self::StoreError(err) => match err { rustical_store::Error::NotFound => StatusCode::NOT_FOUND, rustical_store::Error::AlreadyExists => StatusCode::CONFLICT, rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, _ => StatusCode::INTERNAL_SERVER_ERROR, }, - Error::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, - Error::DavError(err) => StatusCode::try_from(err.status_code().as_u16()) + Self::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::DavError(err) => StatusCode::try_from(err.status_code().as_u16()) .expect("Just converting between versions"), - Error::Unauthorized => StatusCode::UNAUTHORIZED, - Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST, - Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, - Error::NotFound => StatusCode::NOT_FOUND, - Error::IcalError(err) => err.status_code(), - Error::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED, + Self::Unauthorized => StatusCode::UNAUTHORIZED, + Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, + Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound => StatusCode::NOT_FOUND, + Self::IcalError(err) => err.status_code(), + Self::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED, } } } diff --git a/crates/caldav/src/lib.rs b/crates/caldav/src/lib.rs index d527551..9db5f27 100644 --- a/crates/caldav/src/lib.rs +++ b/crates/caldav/src/lib.rs @@ -38,8 +38,8 @@ pub fn caldav_router::new(PrincipalResourceService { auth_provider: auth_provider.clone(), - sub_store: subscription_store.clone(), - cal_store: store.clone(), + sub_store: subscription_store, + cal_store: store, simplified_home_set, }) .axum_router() diff --git a/crates/caldav/src/principal/mod.rs b/crates/caldav/src/principal/mod.rs index b1cd88e..728765b 100644 --- a/crates/caldav/src/principal/mod.rs +++ b/crates/caldav/src/principal/mod.rs @@ -24,7 +24,7 @@ pub struct PrincipalResource { impl ResourceName for PrincipalResource { fn get_name(&self) -> String { - self.principal.id.to_owned() + self.principal.id.clone() } } @@ -56,7 +56,7 @@ impl Resource for PrincipalResource { PrincipalPropWrapperName::Principal(prop) => { PrincipalPropWrapper::Principal(match prop { PrincipalPropName::CalendarUserType => { - PrincipalProp::CalendarUserType(self.principal.principal_type.to_owned()) + PrincipalProp::CalendarUserType(self.principal.principal_type.clone()) } PrincipalPropName::PrincipalUrl => { PrincipalProp::PrincipalUrl(principal_url.into()) diff --git a/crates/caldav/src/principal/prop.rs b/crates/caldav/src/principal/prop.rs index 6777dfb..6285d8b 100644 --- a/crates/caldav/src/principal/prop.rs +++ b/crates/caldav/src/principal/prop.rs @@ -6,7 +6,7 @@ use rustical_store::auth::PrincipalType; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use strum_macros::VariantArray; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "PrincipalPropName")] pub enum PrincipalProp { // Scheduling Extensions to CalDAV (RFC 6638) @@ -34,7 +34,7 @@ pub enum PrincipalProp { CalendarHomeSet(CalendarHomeSet), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] pub Vec); #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] @@ -44,7 +44,7 @@ pub enum PrincipalPropWrapper { Common(CommonPropertiesProp), } -#[derive(XmlSerialize, PartialEq, Clone, VariantArray)] +#[derive(XmlSerialize, PartialEq, Eq, Clone, VariantArray)] pub enum ReportMethod { // We don't actually support principal-match #[xml(ns = "rustical_dav::namespace::NS_DAV")] diff --git a/crates/carddav/src/address_object/prop.rs b/crates/carddav/src/address_object/prop.rs index b2068c9..0a33f5e 100644 --- a/crates/carddav/src/address_object/prop.rs +++ b/crates/carddav/src/address_object/prop.rs @@ -1,7 +1,7 @@ use rustical_dav::extensions::CommonPropertiesProp; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "AddressObjectPropName")] pub enum AddressObjectProp { // WebDAV (RFC 2518) diff --git a/crates/carddav/src/addressbook/methods/mkcol.rs b/crates/carddav/src/addressbook/methods/mkcol.rs index aa4720e..6fdc9af 100644 --- a/crates/carddav/src/addressbook/methods/mkcol.rs +++ b/crates/carddav/src/addressbook/methods/mkcol.rs @@ -8,7 +8,7 @@ use rustical_store::{Addressbook, AddressbookStore, SubscriptionStore, auth::Pri use rustical_xml::{XmlDeserialize, XmlDocument, XmlRootTag}; use tracing::instrument; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct Resourcetype { #[xml(ns = "rustical_dav::namespace::NS_CARDDAV")] addressbook: Option<()>, @@ -16,7 +16,7 @@ pub struct Resourcetype { collection: Option<()>, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct MkcolAddressbookProp { #[xml(ns = "rustical_dav::namespace::NS_DAV")] resourcetype: Option, @@ -27,7 +27,7 @@ pub struct MkcolAddressbookProp { description: Option, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct PropElement { #[xml(ns = "rustical_dav::namespace::NS_DAV")] prop: T, @@ -53,13 +53,13 @@ pub async fn route_mkcol( } let mut request = MkcolRequest::parse_str(&body)?.set.prop; - if let Some("") = request.displayname.as_deref() { - request.displayname = None + if request.displayname.as_deref() == Some("") { + request.displayname = None; } let addressbook = Addressbook { - id: addressbook_id.to_owned(), - principal: principal.to_owned(), + id: addressbook_id.clone(), + principal: principal.clone(), displayname: request.displayname, description: request.description, deleted_at: None, diff --git a/crates/carddav/src/addressbook/methods/post.rs b/crates/carddav/src/addressbook/methods/post.rs index de6b9ec..7b89a5e 100644 --- a/crates/carddav/src/addressbook/methods/post.rs +++ b/crates/carddav/src/addressbook/methods/post.rs @@ -45,12 +45,11 @@ pub async fn route_post( }; let subscription = Subscription { - id: sub_id.to_owned(), + id: sub_id.clone(), push_resource: request .subscription .web_push_subscription - .push_resource - .to_owned(), + .push_resource.clone(), topic: addressbook_resource.0.push_topic, expiration: expires.naive_local(), public_key: request diff --git a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs index a3bf595..ae41dcb 100644 --- a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs +++ b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs @@ -13,7 +13,7 @@ use rustical_ical::AddressObject; use rustical_store::{AddressbookStore, auth::Principal}; use rustical_xml::XmlDeserialize; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] #[xml(ns = "rustical_dav::namespace::NS_DAV")] pub struct AddressbookMultigetRequest { @@ -35,7 +35,7 @@ pub async fn get_objects_addressbook_multiget( for href in &addressbook_multiget.href { if let Some(filename) = href.strip_prefix(path) { - let filename = filename.trim_start_matches("/"); + let filename = filename.trim_start_matches('/'); if let Some(object_id) = filename.strip_suffix(".vcf") { match store .get_object(principal, addressbook_id, object_id, false) @@ -44,7 +44,7 @@ pub async fn get_objects_addressbook_multiget( Ok(object) => result.push(object), Err(rustical_store::Error::NotFound) => not_found.push(href.to_owned()), Err(err) => return Err(err.into()), - }; + } } else { not_found.push(href.to_owned()); continue; diff --git a/crates/carddav/src/addressbook/methods/report/mod.rs b/crates/carddav/src/addressbook/methods/report/mod.rs index a242783..283f806 100644 --- a/crates/carddav/src/addressbook/methods/report/mod.rs +++ b/crates/carddav/src/addressbook/methods/report/mod.rs @@ -26,10 +26,10 @@ pub(crate) enum ReportRequest { } impl ReportRequest { - fn props(&self) -> &PropfindType { + const fn props(&self) -> &PropfindType { match self { - ReportRequest::AddressbookMultiget(AddressbookMultigetRequest { prop, .. }) => prop, - ReportRequest::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, + Self::AddressbookMultiget(AddressbookMultigetRequest { prop, .. }) => prop, + Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, } } } diff --git a/crates/carddav/src/addressbook/prop.rs b/crates/carddav/src/addressbook/prop.rs index 21f3013..def843f 100644 --- a/crates/carddav/src/addressbook/prop.rs +++ b/crates/carddav/src/addressbook/prop.rs @@ -29,7 +29,7 @@ pub enum AddressbookPropWrapper { Common(CommonPropertiesProp), } -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct AddressDataType { #[xml(ty = "attr")] pub content_type: &'static str, @@ -37,7 +37,7 @@ pub struct AddressDataType { pub version: &'static str, } -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct SupportedAddressData { #[xml(ns = "rustical_dav::namespace::NS_CARDDAV", flatten)] address_data_type: &'static [AddressDataType], @@ -60,7 +60,7 @@ impl Default for SupportedAddressData { } } -#[derive(Debug, Clone, XmlSerialize, PartialEq, VariantArray)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq, VariantArray)] pub enum ReportMethod { #[xml(ns = "rustical_dav::namespace::NS_CARDDAV")] AddressbookMultiget, diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index 411698c..d62904b 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -17,7 +17,7 @@ pub struct AddressbookResource(pub(crate) Addressbook); impl ResourceName for AddressbookResource { fn get_name(&self) -> String { - self.0.id.to_owned() + self.0.id.clone() } } @@ -29,7 +29,7 @@ impl SyncTokenExtension for AddressbookResource { impl DavPushExtension for AddressbookResource { fn get_topic(&self) -> String { - self.0.push_topic.to_owned() + self.0.push_topic.clone() } } @@ -65,7 +65,7 @@ impl Resource for AddressbookResource { AddressbookProp::SupportedReportSet(SupportedReportSet::all()) } AddressbookPropName::AddressbookDescription => { - AddressbookProp::AddressbookDescription(self.0.description.to_owned()) + AddressbookProp::AddressbookDescription(self.0.description.clone()) } AddressbookPropName::SupportedAddressData => { AddressbookProp::SupportedAddressData(SupportedAddressData::default()) diff --git a/crates/carddav/src/addressbook/service.rs b/crates/carddav/src/addressbook/service.rs index 8f3b0d4..4ae19d6 100644 --- a/crates/carddav/src/addressbook/service.rs +++ b/crates/carddav/src/addressbook/service.rs @@ -26,7 +26,7 @@ pub struct AddressbookResourceService AddressbookResourceService { - pub fn new(addr_store: Arc, sub_store: Arc) -> Self { + pub const fn new(addr_store: Arc, sub_store: Arc) -> Self { Self { addr_store, sub_store, diff --git a/crates/carddav/src/error.rs b/crates/carddav/src/error.rs index 5bc0688..a79df8f 100644 --- a/crates/carddav/src/error.rs +++ b/crates/carddav/src/error.rs @@ -30,20 +30,20 @@ pub enum Error { } impl Error { - pub fn status_code(&self) -> StatusCode { + #[must_use] pub const fn status_code(&self) -> StatusCode { match self { - Error::StoreError(err) => match err { + Self::StoreError(err) => match err { rustical_store::Error::NotFound => StatusCode::NOT_FOUND, rustical_store::Error::AlreadyExists => StatusCode::CONFLICT, rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, _ => StatusCode::INTERNAL_SERVER_ERROR, }, - Error::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, - Error::DavError(err) => err.status_code(), - Error::Unauthorized => StatusCode::UNAUTHORIZED, - Error::XmlDecodeError(_) => StatusCode::BAD_REQUEST, - Error::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, - Error::NotFound => StatusCode::NOT_FOUND, + Self::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::DavError(err) => err.status_code(), + Self::Unauthorized => StatusCode::UNAUTHORIZED, + Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, + Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound => StatusCode::NOT_FOUND, Self::IcalError(err) => err.status_code(), } } diff --git a/crates/carddav/src/lib.rs b/crates/carddav/src/lib.rs index ce87be6..f9638c2 100644 --- a/crates/carddav/src/lib.rs +++ b/crates/carddav/src/lib.rs @@ -38,15 +38,15 @@ pub fn carddav_router, ) -> Router { let principal_service = PrincipalResourceService::new( - store.clone(), + store, auth_provider.clone(), - subscription_store.clone(), + subscription_store, ); Router::new() .nest( prefix, RootResourceService::<_, Principal, CardDavPrincipalUri>::new( - principal_service.clone(), + principal_service, ) .axum_router() .layer(AuthenticationLayer::new(auth_provider)) diff --git a/crates/carddav/src/principal/mod.rs b/crates/carddav/src/principal/mod.rs index 39daa7f..bb43c10 100644 --- a/crates/carddav/src/principal/mod.rs +++ b/crates/carddav/src/principal/mod.rs @@ -20,7 +20,7 @@ pub struct PrincipalResource { impl ResourceName for PrincipalResource { fn get_name(&self) -> String { - self.principal.id.to_owned() + self.principal.id.clone() } } diff --git a/crates/carddav/src/principal/prop.rs b/crates/carddav/src/principal/prop.rs index 8bf79a4..2689589 100644 --- a/crates/carddav/src/principal/prop.rs +++ b/crates/carddav/src/principal/prop.rs @@ -4,7 +4,7 @@ use rustical_dav::{ }; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "PrincipalPropName")] pub enum PrincipalProp { // WebDAV Access Control (RFC 3744) @@ -27,7 +27,7 @@ pub enum PrincipalProp { PrincipalAddress(Option), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct AddressbookHomeSet(#[xml(ty = "untagged", flatten)] pub Vec); #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] diff --git a/crates/carddav/src/principal/service.rs b/crates/carddav/src/principal/service.rs index 18f734f..22b07bb 100644 --- a/crates/carddav/src/principal/service.rs +++ b/crates/carddav/src/principal/service.rs @@ -34,7 +34,7 @@ impl Clon impl PrincipalResourceService { - pub fn new(addr_store: Arc, auth_provider: Arc, sub_store: Arc) -> Self { + pub const fn new(addr_store: Arc, auth_provider: Arc, sub_store: Arc) -> Self { Self { addr_store, auth_provider, diff --git a/crates/dav/src/error.rs b/crates/dav/src/error.rs index 207ffb1..ab614cd 100644 --- a/crates/dav/src/error.rs +++ b/crates/dav/src/error.rs @@ -35,7 +35,7 @@ pub enum Error { } impl Error { - pub fn status_code(&self) -> StatusCode { + #[must_use] pub const fn status_code(&self) -> StatusCode { match self { Self::InternalError => StatusCode::INTERNAL_SERVER_ERROR, Self::NotFound => StatusCode::NOT_FOUND, @@ -50,8 +50,8 @@ impl Error { | XmlError::InvalidValue(_) => StatusCode::UNPROCESSABLE_ENTITY, _ => StatusCode::BAD_REQUEST, }, - Error::PropReadOnly => StatusCode::CONFLICT, - Error::PreconditionFailed => StatusCode::PRECONDITION_FAILED, + Self::PropReadOnly => StatusCode::CONFLICT, + Self::PreconditionFailed => StatusCode::PRECONDITION_FAILED, Self::IOError(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::Forbidden => StatusCode::FORBIDDEN, } @@ -68,7 +68,7 @@ impl axum::response::IntoResponse for Error { } let mut resp = axum::response::Response::builder().status(self.status_code()); - if matches!(&self, &Error::Unauthorized) { + if matches!(&self, &Self::Unauthorized) { resp.headers_mut() .expect("This must always work") .insert("WWW-Authenticate", "Basic".parse().unwrap()); diff --git a/crates/dav/src/extensions/common.rs b/crates/dav/src/extensions/common.rs index 91898f3..b9ad129 100644 --- a/crates/dav/src/extensions/common.rs +++ b/crates/dav/src/extensions/common.rs @@ -40,7 +40,7 @@ pub trait CommonPropertiesExtension: Resource { CommonPropertiesProp::Resourcetype(self.get_resourcetype()) } CommonPropertiesPropName::Displayname => { - CommonPropertiesProp::Displayname(self.get_displayname().map(|s| s.to_string())) + CommonPropertiesProp::Displayname(self.get_displayname().map(std::string::ToString::to_string)) } CommonPropertiesPropName::CurrentUserPrincipal => { CommonPropertiesProp::CurrentUserPrincipal( diff --git a/crates/dav/src/extensions/synctoken.rs b/crates/dav/src/extensions/synctoken.rs index ca9e48e..a75d1c4 100644 --- a/crates/dav/src/extensions/synctoken.rs +++ b/crates/dav/src/extensions/synctoken.rs @@ -1,6 +1,6 @@ use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, PropName, EnumVariants)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)] #[xml(unit_variants_ident = "SyncTokenExtensionPropName")] pub enum SyncTokenExtensionProp { // Collection Synchronization (RFC 6578) diff --git a/crates/dav/src/header/depth.rs b/crates/dav/src/header/depth.rs index 21592c6..70baa92 100644 --- a/crates/dav/src/header/depth.rs +++ b/crates/dav/src/header/depth.rs @@ -19,7 +19,7 @@ impl IntoResponse for InvalidDepthHeader { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Depth { Zero, One, @@ -29,9 +29,9 @@ pub enum Depth { impl ValueSerialize for Depth { fn serialize(&self) -> String { match self { - Depth::Zero => "0", - Depth::One => "1", - Depth::Infinity => "infinity", + Self::Zero => "0", + Self::One => "1", + Self::Infinity => "infinity", } .to_owned() } @@ -55,9 +55,9 @@ impl TryFrom<&[u8]> for Depth { fn try_from(value: &[u8]) -> Result { match value { - b"0" => Ok(Depth::Zero), - b"1" => Ok(Depth::One), - b"Infinity" | b"infinity" => Ok(Depth::Infinity), + b"0" => Ok(Self::Zero), + b"1" => Ok(Self::One), + b"Infinity" | b"infinity" => Ok(Self::Infinity), _ => Err(InvalidDepthHeader), } } diff --git a/crates/dav/src/header/overwrite.rs b/crates/dav/src/header/overwrite.rs index 06cbb9e..3cd646e 100644 --- a/crates/dav/src/header/overwrite.rs +++ b/crates/dav/src/header/overwrite.rs @@ -14,7 +14,7 @@ impl IntoResponse for InvalidOverwriteHeader { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct Overwrite(pub bool); impl Default for Overwrite { diff --git a/crates/dav/src/privileges.rs b/crates/dav/src/privileges.rs index beb3347..bc7ebb2 100644 --- a/crates/dav/src/privileges.rs +++ b/crates/dav/src/privileges.rs @@ -41,13 +41,13 @@ impl XmlSerialize for UserPrivilegeSet { } } -#[derive(Debug, Clone, Default, PartialEq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct UserPrivilegeSet { privileges: HashSet, } impl UserPrivilegeSet { - pub fn has(&self, privilege: &UserPrivilege) -> bool { + #[must_use] pub fn has(&self, privilege: &UserPrivilege) -> bool { if (privilege == &UserPrivilege::WriteProperties || privilege == &UserPrivilege::WriteContent) && self.privileges.contains(&UserPrivilege::Write) @@ -57,13 +57,13 @@ impl UserPrivilegeSet { self.privileges.contains(privilege) || self.privileges.contains(&UserPrivilege::All) } - pub fn all() -> Self { + #[must_use] pub fn all() -> Self { Self { privileges: HashSet::from([UserPrivilege::All]), } } - pub fn owner_only(is_owner: bool) -> Self { + #[must_use] pub fn owner_only(is_owner: bool) -> Self { if is_owner { Self::all() } else { @@ -71,7 +71,7 @@ impl UserPrivilegeSet { } } - pub fn owner_read(is_owner: bool) -> Self { + #[must_use] pub fn owner_read(is_owner: bool) -> Self { if is_owner { Self::read_only() } else { @@ -79,7 +79,7 @@ impl UserPrivilegeSet { } } - pub fn owner_write_properties(is_owner: bool) -> Self { + #[must_use] pub fn owner_write_properties(is_owner: bool) -> Self { // Content is read-only but we can write properties if is_owner { Self::write_properties() @@ -88,7 +88,7 @@ impl UserPrivilegeSet { } } - pub fn read_only() -> Self { + #[must_use] pub fn read_only() -> Self { Self { privileges: HashSet::from([ UserPrivilege::Read, @@ -98,7 +98,7 @@ impl UserPrivilegeSet { } } - pub fn write_properties() -> Self { + #[must_use] pub fn write_properties() -> Self { Self { privileges: HashSet::from([ UserPrivilege::Read, diff --git a/crates/dav/src/resource/axum_methods.rs b/crates/dav/src/resource/axum_methods.rs index 638f9ee..98b6fed 100644 --- a/crates/dav/src/resource/axum_methods.rs +++ b/crates/dav/src/resource/axum_methods.rs @@ -9,42 +9,42 @@ pub type MethodFunction = pub trait AxumMethods: Sized + Send + Sync + 'static { #[inline] - fn report() -> Option> { + #[must_use] fn report() -> Option> { None } #[inline] - fn get() -> Option> { + #[must_use] fn get() -> Option> { None } #[inline] - fn post() -> Option> { + #[must_use] fn post() -> Option> { None } #[inline] - fn mkcol() -> Option> { + #[must_use] fn mkcol() -> Option> { None } #[inline] - fn mkcalendar() -> Option> { + #[must_use] fn mkcalendar() -> Option> { None } #[inline] - fn put() -> Option> { + #[must_use] fn put() -> Option> { None } #[inline] - fn import() -> Option> { + #[must_use] fn import() -> Option> { None } #[inline] - fn allow_header() -> Allow { + #[must_use] fn allow_header() -> Allow { let mut allow = vec![ Method::from_str("PROPFIND").unwrap(), Method::from_str("PROPPATCH").unwrap(), diff --git a/crates/dav/src/resource/axum_service.rs b/crates/dav/src/resource/axum_service.rs index 20487b5..8cbdb37 100644 --- a/crates/dav/src/resource/axum_service.rs +++ b/crates/dav/src/resource/axum_service.rs @@ -23,7 +23,7 @@ pub struct AxumService { } impl AxumService { - pub fn new(resource_service: RS) -> Self { + pub const fn new(resource_service: RS) -> Self { Self { resource_service } } } @@ -103,7 +103,7 @@ where } } _ => {} - }; + } Box::pin(async move { Ok(Response::builder() .status(StatusCode::METHOD_NOT_ALLOWED) diff --git a/crates/dav/src/resource/methods/copy.rs b/crates/dav/src/resource/methods/copy.rs index daa11a8..bec1372 100644 --- a/crates/dav/src/resource/methods/copy.rs +++ b/crates/dav/src/resource/methods/copy.rs @@ -12,7 +12,7 @@ use serde::Deserialize; use tracing::instrument; #[instrument(skip(path, resource_service,))] -pub(crate) async fn axum_route_copy( +pub async fn axum_route_copy( Path(path): Path, State(resource_service): State, depth: Option, diff --git a/crates/dav/src/resource/methods/delete.rs b/crates/dav/src/resource/methods/delete.rs index d7b5c47..febc887 100644 --- a/crates/dav/src/resource/methods/delete.rs +++ b/crates/dav/src/resource/methods/delete.rs @@ -7,7 +7,7 @@ use axum_extra::TypedHeader; use headers::{IfMatch, IfNoneMatch}; use http::HeaderMap; -pub(crate) async fn axum_route_delete( +pub async fn axum_route_delete( Path(path): Path, State(resource_service): State, principal: R::Principal, @@ -24,8 +24,7 @@ pub(crate) async fn axum_route_delete( } let no_trash = header_map .get("X-No-Trashbin") - .map(|val| matches!(val.to_str(), Ok("1"))) - .unwrap_or(false); + .is_some_and(|val| matches!(val.to_str(), Ok("1"))); route_delete( &path, &principal, diff --git a/crates/dav/src/resource/methods/mod.rs b/crates/dav/src/resource/methods/mod.rs index a8610a3..2b770af 100644 --- a/crates/dav/src/resource/methods/mod.rs +++ b/crates/dav/src/resource/methods/mod.rs @@ -4,8 +4,8 @@ mod mv; mod propfind; mod proppatch; -pub(crate) use copy::axum_route_copy; -pub(crate) use delete::axum_route_delete; -pub(crate) use mv::axum_route_move; -pub(crate) use propfind::axum_route_propfind; -pub(crate) use proppatch::axum_route_proppatch; +pub use copy::axum_route_copy; +pub use delete::axum_route_delete; +pub use mv::axum_route_move; +pub use propfind::axum_route_propfind; +pub use proppatch::axum_route_proppatch; diff --git a/crates/dav/src/resource/methods/mv.rs b/crates/dav/src/resource/methods/mv.rs index a2ce1d4..a10d5d8 100644 --- a/crates/dav/src/resource/methods/mv.rs +++ b/crates/dav/src/resource/methods/mv.rs @@ -12,7 +12,7 @@ use serde::Deserialize; use tracing::instrument; #[instrument(skip(path, resource_service,))] -pub(crate) async fn axum_route_move( +pub async fn axum_route_move( Path(path): Path, State(resource_service): State, depth: Option, diff --git a/crates/dav/src/resource/methods/propfind.rs b/crates/dav/src/resource/methods/propfind.rs index 3f630cb..361c3e4 100644 --- a/crates/dav/src/resource/methods/propfind.rs +++ b/crates/dav/src/resource/methods/propfind.rs @@ -15,7 +15,7 @@ type RSMultistatus = MultistatusElement< >; #[instrument(skip(path, resource_service, puri))] -pub(crate) async fn axum_route_propfind( +pub async fn axum_route_propfind( Path(path): Path, State(resource_service): State, depth: Depth, @@ -36,7 +36,7 @@ pub(crate) async fn axum_route_propfind( .await } -pub(crate) async fn route_propfind( +pub async fn route_propfind( path_components: &R::PathComponents, path: &str, body: &str, diff --git a/crates/dav/src/resource/methods/proppatch.rs b/crates/dav/src/resource/methods/proppatch.rs index 4ba6adf..dc24821 100644 --- a/crates/dav/src/resource/methods/proppatch.rs +++ b/crates/dav/src/resource/methods/proppatch.rs @@ -61,7 +61,7 @@ enum Operation { #[xml(ns = "crate::namespace::NS_DAV")] struct PropertyupdateElement(#[xml(ty = "untagged", flatten)] Vec>); -pub(crate) async fn axum_route_proppatch( +pub async fn axum_route_proppatch( Path(path): Path, State(resource_service): State, principal: R::Principal, @@ -71,7 +71,7 @@ pub(crate) async fn axum_route_proppatch( route_proppatch(&path, uri.path(), &body, &principal, &resource_service).await } -pub(crate) async fn route_proppatch( +pub async fn route_proppatch( path_components: &R::PathComponents, path: &str, body: &str, @@ -96,7 +96,7 @@ pub(crate) async fn route_proppatch( let mut props_conflict = Vec::new(); let mut props_not_found = Vec::new(); - for operation in operations.into_iter() { + for operation in operations { match operation { Operation::Set(SetPropertyElement { prop: SetPropertyPropWrapperWrapper(properties), @@ -113,7 +113,7 @@ pub(crate) async fn route_proppatch( Err(Error::PropReadOnly) => props_conflict .push((ns.map(NamespaceOwned::from), propname.to_owned())), Err(err) => return Err(err.into()), - }; + } } SetPropertyPropWrapper::Invalid(invalid) => { let propname = invalid.tag_name(); @@ -131,7 +131,7 @@ pub(crate) async fn route_proppatch( // This happens in following cases: // - read-only properties with #[serde(skip_deserializing)] // - internal properties - props_conflict.push(full_propname) + props_conflict.push(full_propname); } else { props_not_found.push((None, propname)); } @@ -154,7 +154,7 @@ pub(crate) async fn route_proppatch( }, // I guess removing a nonexisting property should be successful :) Err(_) => props_ok.push((None, propname)), - }; + } } } } diff --git a/crates/dav/src/resource/mod.rs b/crates/dav/src/resource/mod.rs index f55a6f8..9717ce1 100644 --- a/crates/dav/src/resource/mod.rs +++ b/crates/dav/src/resource/mod.rs @@ -42,7 +42,7 @@ pub trait Resource: Clone + Send + 'static { fn get_resourcetype(&self) -> Resourcetype; - fn list_props() -> Vec<(Option>, &'static str)> { + #[must_use] fn list_props() -> Vec<(Option>, &'static str)> { Self::Prop::variant_names() } @@ -106,13 +106,13 @@ pub trait Resource: Clone + Send + 'static { fn parse_propfind( body: &str, ) -> Result::Names>, rustical_xml::XmlError> { - if !body.is_empty() { - PropfindElement::parse_str(body) - } else { + if body.is_empty() { Ok(PropfindElement { prop: PropfindType::Allprop, include: None, }) + } else { + PropfindElement::parse_str(body) } } @@ -139,7 +139,7 @@ pub trait Resource: Clone + Send + 'static { .collect_vec(); return Ok(ResponseElement { - href: path.to_owned(), + href: path.clone(), propstat: vec![PropstatWrapper::TagList(PropstatElement { prop: TagList::from(props), status: StatusCode::OK, @@ -181,7 +181,7 @@ pub trait Resource: Clone + Send + 'static { })); } Ok(ResponseElement { - href: path.to_owned(), + href: path.clone(), propstat: propstats, ..Default::default() }) diff --git a/crates/dav/src/resources/root.rs b/crates/dav/src/resources/root.rs index 9d59fd8..7a1eb47 100644 --- a/crates/dav/src/resources/root.rs +++ b/crates/dav/src/resources/root.rs @@ -63,7 +63,7 @@ pub struct RootResourceService RootResourceService { - pub fn new(principal_resource_service: PRS) -> Self { + pub const fn new(principal_resource_service: PRS) -> Self { Self(principal_resource_service, PhantomData, PhantomData) } } @@ -88,7 +88,7 @@ where async fn get_resource( &self, - _: &(), + (): &(), _show_deleted: bool, ) -> Result { Ok(RootResource::::default()) diff --git a/crates/dav/src/xml/group.rs b/crates/dav/src/xml/group.rs index fe54805..fce2d28 100644 --- a/crates/dav/src/xml/group.rs +++ b/crates/dav/src/xml/group.rs @@ -1,8 +1,8 @@ use crate::xml::HrefElement; use rustical_xml::{XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub Vec); -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub Vec); diff --git a/crates/dav/src/xml/href.rs b/crates/dav/src/xml/href.rs index a392663..8faba2c 100644 --- a/crates/dav/src/xml/href.rs +++ b/crates/dav/src/xml/href.rs @@ -1,14 +1,14 @@ use derive_more::From; use rustical_xml::{XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, Debug, Clone, From, PartialEq)] +#[derive(XmlDeserialize, XmlSerialize, Debug, Clone, From, PartialEq, Eq)] pub struct HrefElement { #[xml(ns = "crate::namespace::NS_DAV")] pub href: String, } impl HrefElement { - pub fn new(href: String) -> Self { + #[must_use] pub const fn new(href: String) -> Self { Self { href } } } diff --git a/crates/dav/src/xml/multistatus.rs b/crates/dav/src/xml/multistatus.rs index 0e2cc0b..689a105 100644 --- a/crates/dav/src/xml/multistatus.rs +++ b/crates/dav/src/xml/multistatus.rs @@ -26,7 +26,7 @@ fn xml_serialize_status( namespaces: &HashMap, writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { - XmlSerialize::serialize(&format!("HTTP/1.1 {}", status), ns, tag, namespaces, writer) + XmlSerialize::serialize(&format!("HTTP/1.1 {status}"), ns, tag, namespaces, writer) } #[derive(XmlSerialize)] @@ -64,7 +64,7 @@ fn xml_serialize_optional_status( writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { XmlSerialize::serialize( - &val.map(|status| format!("HTTP/1.1 {}", status)), + &val.map(|status| format!("HTTP/1.1 {status}")), ns, tag, namespaces, diff --git a/crates/dav/src/xml/propfind.rs b/crates/dav/src/xml/propfind.rs index 8962268..7e85ed7 100644 --- a/crates/dav/src/xml/propfind.rs +++ b/crates/dav/src/xml/propfind.rs @@ -15,7 +15,7 @@ pub struct PropfindElement { pub include: Option>, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PropElement( // valid pub Vec, @@ -82,7 +82,7 @@ impl XmlDeserialize for PropElement { } } -#[derive(Debug, Clone, XmlDeserialize, PartialEq)] +#[derive(Debug, Clone, XmlDeserialize, PartialEq, Eq)] pub enum PropfindType { #[xml(ns = "crate::namespace::NS_DAV")] Propname, diff --git a/crates/dav/src/xml/report_set.rs b/crates/dav/src/xml/report_set.rs index 4134c27..e5c5323 100644 --- a/crates/dav/src/xml/report_set.rs +++ b/crates/dav/src/xml/report_set.rs @@ -2,7 +2,7 @@ use rustical_xml::XmlSerialize; use strum::VariantArray; // RFC 3253 section-3.1.5 -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct SupportedReportSet { #[xml(flatten)] #[xml(ns = "crate::namespace::NS_DAV")] @@ -10,7 +10,7 @@ pub struct SupportedReportSet { } impl SupportedReportSet { - pub fn new(methods: Vec) -> Self { + #[must_use] pub fn new(methods: Vec) -> Self { Self { supported_report: methods .into_iter() @@ -27,7 +27,7 @@ impl SupportedReportSet { } } -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct ReportWrapper { #[xml(ns = "crate::namespace::NS_DAV")] report: T, diff --git a/crates/dav/src/xml/resourcetype.rs b/crates/dav/src/xml/resourcetype.rs index 8b9dcb5..0a00bde 100644 --- a/crates/dav/src/xml/resourcetype.rs +++ b/crates/dav/src/xml/resourcetype.rs @@ -1,9 +1,9 @@ use rustical_xml::XmlSerialize; -#[derive(Debug, Clone, PartialEq, XmlSerialize)] +#[derive(Debug, Clone, PartialEq, Eq, XmlSerialize)] pub struct Resourcetype(#[xml(flatten, ty = "untagged")] pub &'static [ResourcetypeInner]); -#[derive(Debug, Clone, PartialEq, XmlSerialize)] +#[derive(Debug, Clone, PartialEq, Eq, XmlSerialize)] pub struct ResourcetypeInner( #[xml(ty = "namespace")] pub Option>, #[xml(ty = "tag_name")] pub &'static str, diff --git a/crates/dav/src/xml/sync_collection.rs b/crates/dav/src/xml/sync_collection.rs index 50d14a8..30fa10b 100644 --- a/crates/dav/src/xml/sync_collection.rs +++ b/crates/dav/src/xml/sync_collection.rs @@ -2,7 +2,7 @@ use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize, XmlRootTag} use super::PropfindType; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum SyncLevel { One, Infinity, @@ -25,15 +25,15 @@ impl ValueDeserialize for SyncLevel { impl ValueSerialize for SyncLevel { fn serialize(&self) -> String { match self { - SyncLevel::One => "1", - SyncLevel::Infinity => "Infinity", + Self::One => "1", + Self::Infinity => "Infinity", } .to_owned() } } // https://datatracker.ietf.org/doc/html/rfc5323#section-5.17 -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct LimitElement { #[xml(ns = "crate::namespace::NS_DAV")] pub nresults: NresultsElement, @@ -53,7 +53,7 @@ impl From for u64 { } } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct NresultsElement(#[xml(ty = "text")] u64); #[derive(XmlDeserialize, Clone, Debug, PartialEq, XmlRootTag)] diff --git a/crates/dav/src/xml/tag_list.rs b/crates/dav/src/xml/tag_list.rs index 506d22d..41779e3 100644 --- a/crates/dav/src/xml/tag_list.rs +++ b/crates/dav/src/xml/tag_list.rs @@ -6,7 +6,7 @@ use quick_xml::{ use rustical_xml::{NamespaceOwned, XmlSerialize}; use std::collections::HashMap; -#[derive(Clone, Debug, PartialEq, From)] +#[derive(Clone, Debug, PartialEq, Eq, From)] pub struct TagList(Vec<(Option, String)>); impl XmlSerialize for TagList { @@ -18,13 +18,12 @@ impl XmlSerialize for TagList { writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { let prefix = ns - .map(|ns| namespaces.get(&ns)) - .unwrap_or(None) + .and_then(|ns| namespaces.get(&ns)) .map(|prefix| { - if !prefix.is_empty() { - format!("{prefix}:") - } else { + if prefix.is_empty() { String::new() + } else { + format!("{prefix}:") } }); let has_prefix = prefix.is_some(); diff --git a/crates/dav_push/src/lib.rs b/crates/dav_push/src/lib.rs index 835c530..431061e 100644 --- a/crates/dav_push/src/lib.rs +++ b/crates/dav_push/src/lib.rs @@ -125,7 +125,7 @@ impl DavPushController { subsciption.id, subsciption.topic ); self.try_delete_subscription(&subsciption.id).await; - }; + } } if let Err(err) = self.send_payload(&payload, &subsciption).await { @@ -207,7 +207,7 @@ enum NotifierError { impl NotifierError { // Decide whether the error should cause the subscription to be removed - pub fn is_permament_error(&self) -> bool { + pub const fn is_permament_error(&self) -> bool { match self { Self::InvalidPublicKeyType(_) | Self::InvalidEndpointUrl(_) diff --git a/crates/dav_push/src/prop.rs b/crates/dav_push/src/prop.rs index f995967..01237a1 100644 --- a/crates/dav_push/src/prop.rs +++ b/crates/dav_push/src/prop.rs @@ -1,7 +1,7 @@ use rustical_dav::header::Depth; use rustical_xml::{Unparsed, XmlDeserialize, XmlSerialize}; -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub enum Transport { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] WebPush, @@ -33,12 +33,12 @@ pub enum Trigger { PropertyUpdate(PropertyUpdate), } -#[derive(XmlSerialize, XmlDeserialize, PartialEq, Clone, Debug)] +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Clone, Debug)] pub struct ContentUpdate( #[xml(rename = "depth", ns = "rustical_dav::namespace::NS_DAV")] pub Depth, ); -#[derive(XmlSerialize, PartialEq, Clone, Debug)] +#[derive(XmlSerialize, PartialEq, Eq, Clone, Debug)] pub struct PropertyUpdate( #[xml(rename = "depth", ns = "rustical_dav::namespace::NS_DAV")] pub Depth, ); diff --git a/crates/dav_push/src/register.rs b/crates/dav_push/src/register.rs index 4a159dc..d721050 100644 --- a/crates/dav_push/src/register.rs +++ b/crates/dav_push/src/register.rs @@ -15,7 +15,7 @@ pub struct WebPushSubscription { pub auth_secret: String, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct SubscriptionPublicKey { #[xml(ty = "attr", rename = "type")] pub ty: String, diff --git a/crates/frontend/src/config.rs b/crates/frontend/src/config.rs index dee7e71..8d0ef26 100644 --- a/crates/frontend/src/config.rs +++ b/crates/frontend/src/config.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -fn default_true() -> bool { +const fn default_true() -> bool { true } diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index c16a58d..0aee30b 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -106,11 +106,11 @@ pub fn frontend_router(auth_provider: Arc .route("/", post(post_nextcloud_login)) .layer(Extension(nextcloud_flows)) .layer(Extension(auth_provider.clone())) - .layer(AuthenticationLayer::new(auth_provider.clone())) + .layer(AuthenticationLayer::new(auth_provider)) .layer(middleware::from_fn(unauthorized_handler)) } diff --git a/crates/frontend/src/nextcloud_login/routes.rs b/crates/frontend/src/nextcloud_login/routes.rs index 3510a75..ce25b5e 100644 --- a/crates/frontend/src/nextcloud_login/routes.rs +++ b/crates/frontend/src/nextcloud_login/routes.rs @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize}; use std::sync::Arc; use tracing::instrument; -pub(crate) async fn post_nextcloud_login( +pub async fn post_nextcloud_login( Extension(state): Extension>, TypedHeader(user_agent): TypedHeader, Host(host): Host, @@ -35,9 +35,9 @@ pub(crate) async fn post_nextcloud_login( flows.insert( flow_id.clone(), NextcloudFlow { - app_name: app_name.to_owned(), + app_name: app_name.clone(), created_at: Utc::now(), - token: token.to_owned(), + token: token.clone(), response: None, }, ); @@ -52,11 +52,11 @@ pub(crate) async fn post_nextcloud_login( #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub(crate) struct NextcloudPollForm { +pub struct NextcloudPollForm { token: String, } -pub(crate) async fn post_nextcloud_poll( +pub async fn post_nextcloud_poll( Extension(state): Extension>, Path(flow_id): Path, Extension(auth_provider): Extension>, @@ -75,8 +75,8 @@ pub(crate) async fn post_nextcloud_poll( auth_provider .add_app_token( &response.login_name, - flow.app_name.to_owned(), - response.app_password.to_owned(), + flow.app_name.clone(), + response.app_password.clone(), ) .await?; flows.remove(&flow_id); @@ -98,7 +98,7 @@ struct NextcloudLoginPage { } #[instrument(skip(state))] -pub(crate) async fn get_nextcloud_flow( +pub async fn get_nextcloud_flow( Extension(state): Extension>, Path(flow_id): Path, user: Principal, @@ -107,7 +107,7 @@ pub(crate) async fn get_nextcloud_flow( Ok(Html( NextcloudLoginPage { username: user.displayname.unwrap_or(user.id), - app_name: flow.app_name.to_owned(), + app_name: flow.app_name.clone(), } .render() .unwrap(), @@ -119,7 +119,7 @@ pub(crate) async fn get_nextcloud_flow( } #[derive(Debug, Clone, Deserialize, Serialize)] -pub(crate) struct NextcloudAuthorizeForm { +pub struct NextcloudAuthorizeForm { app_name: String, } @@ -130,7 +130,7 @@ struct NextcloudLoginSuccessPage { } #[instrument(skip(state))] -pub(crate) async fn post_nextcloud_flow( +pub async fn post_nextcloud_flow( user: Principal, Extension(state): Extension>, Path(flow_id): Path, @@ -141,12 +141,12 @@ pub(crate) async fn post_nextcloud_flow( flow.app_name = form.app_name; flow.response = Some(NextcloudSuccessResponse { server: format!("https://{host}"), - login_name: user.id.to_owned(), + login_name: user.id.clone(), app_password: generate_app_token(), }); Ok(Html( NextcloudLoginSuccessPage { - app_name: flow.app_name.to_owned(), + app_name: flow.app_name.clone(), } .render() .unwrap(), diff --git a/crates/frontend/src/routes/app_token.rs b/crates/frontend/src/routes/app_token.rs index fdf174c..6fc6e26 100644 --- a/crates/frontend/src/routes/app_token.rs +++ b/crates/frontend/src/routes/app_token.rs @@ -40,7 +40,7 @@ pub struct AppleConfig { } #[derive(Debug, Clone, Deserialize)] -pub(crate) struct PostAppTokenForm { +pub struct PostAppTokenForm { name: String, #[serde(default)] apple: bool, @@ -57,7 +57,7 @@ pub async fn route_post_app_token( assert_eq!(user_id, user.id); let token = generate_app_token(); let mut token_id = auth_provider - .add_app_token(&user.id, name.to_owned(), token.clone()) + .add_app_token(&user.id, name.clone(), token.clone()) .await?; // Get first 4 characters of token identifier token_id.truncate(4); @@ -70,7 +70,7 @@ pub async fn route_post_app_token( hostname: hostname.clone(), caldav_principal_url: format!("https://{hostname}/caldav-compat/principal/{user_id}"), carddav_principal_url: format!("https://{hostname}/carddav/principal/{user_id}"), - user: user.id.to_owned(), + user: user.id.clone(), token, caldav_profile_uuid: Uuid::new_v4(), carddav_profile_uuid: Uuid::new_v4(), diff --git a/crates/ical/src/address_object.rs b/crates/ical/src/address_object.rs index 5e3e987..5726036 100644 --- a/crates/ical/src/address_object.rs +++ b/crates/ical/src/address_object.rs @@ -45,32 +45,32 @@ impl AddressObject { Ok(Self { id, vcf, vcard }) } - pub fn get_id(&self) -> &str { + #[must_use] pub fn get_id(&self) -> &str { &self.id } - pub fn get_etag(&self) -> String { + #[must_use] pub fn get_etag(&self) -> String { let mut hasher = Sha256::new(); hasher.update(self.get_id()); hasher.update(self.get_vcf()); format!("\"{:x}\"", hasher.finalize()) } - pub fn get_vcf(&self) -> &str { + #[must_use] pub fn get_vcf(&self) -> &str { &self.vcf } - pub fn get_anniversary(&self) -> Option<(CalDateTime, bool)> { + #[must_use] pub fn get_anniversary(&self) -> Option<(CalDateTime, bool)> { let prop = self.vcard.get_property("ANNIVERSARY")?.value.as_deref()?; CalDateTime::parse_vcard(prop).ok() } - pub fn get_birthday(&self) -> Option<(CalDateTime, bool)> { + #[must_use] pub fn get_birthday(&self) -> Option<(CalDateTime, bool)> { let prop = self.vcard.get_property("BDAY")?.value.as_deref()?; CalDateTime::parse_vcard(prop).ok() } - pub fn get_full_name(&self) -> Option<&str> { + #[must_use] pub fn get_full_name(&self) -> Option<&str> { let prop = self.vcard.get_property("FN")?; prop.value.as_deref() } @@ -94,7 +94,7 @@ impl AddressObject { let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default(); Some(CalendarObject::from_ics(format!( - r#"BEGIN:VCALENDAR + r"BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//github.com/lennart-k/rustical birthday calendar//EN @@ -111,7 +111,7 @@ ACTION:DISPLAY DESCRIPTION:💍 {fullname}{year_suffix} END:VALARM END:VEVENT -END:VCALENDAR"#, +END:VCALENDAR", ))?) } else { None @@ -135,7 +135,7 @@ END:VCALENDAR"#, let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default(); Some(CalendarObject::from_ics(format!( - r#"BEGIN:VCALENDAR + r"BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//github.com/lennart-k/rustical birthday calendar//EN @@ -152,7 +152,7 @@ ACTION:DISPLAY DESCRIPTION:🎂 {fullname}{year_suffix} END:VALARM END:VEVENT -END:VCALENDAR"#, +END:VCALENDAR", ))?) } else { None diff --git a/crates/ical/src/error.rs b/crates/ical/src/error.rs index 0821e5f..5805901 100644 --- a/crates/ical/src/error.rs +++ b/crates/ical/src/error.rs @@ -24,7 +24,7 @@ pub enum Error { } impl Error { - pub fn status_code(&self) -> StatusCode { + #[must_use] pub const fn status_code(&self) -> StatusCode { match self { Self::InvalidData(_) => StatusCode::BAD_REQUEST, Self::MissingCalendar | Self::MissingContact => StatusCode::BAD_REQUEST, diff --git a/crates/ical/src/icalendar/event.rs b/crates/ical/src/icalendar/event.rs index f07918f..25ad480 100644 --- a/crates/ical/src/icalendar/event.rs +++ b/crates/ical/src/icalendar/event.rs @@ -15,7 +15,7 @@ pub struct EventObject { } impl EventObject { - pub fn get_uid(&self) -> &str { + #[must_use] pub fn get_uid(&self) -> &str { self.event.get_uid() } @@ -43,7 +43,7 @@ impl EventObject { if let Some(dtend) = self.get_dtend()? { return Ok(Some(dtend)); - }; + } let duration = self.event.get_duration().unwrap_or(Duration::days(1)); @@ -96,7 +96,7 @@ impl EventObject { &self, start: Option>, end: Option>, - overrides: &[EventObject], + overrides: &[Self], ) -> Result, Error> { if let Some(mut rrule_set) = self.recurrence_ruleset()? { if let Some(start) = start { @@ -150,7 +150,7 @@ impl EventObject { ev.set_property(Property { name: "RECURRENCE-ID".to_string(), - value: Some(dateformat.to_owned()), + value: Some(dateformat.clone()), params: None, }); ev.set_property(Property { diff --git a/crates/ical/src/icalendar/object.rs b/crates/ical/src/icalendar/object.rs index 20be88e..9dbe7c5 100644 --- a/crates/ical/src/icalendar/object.rs +++ b/crates/ical/src/icalendar/object.rs @@ -26,11 +26,11 @@ pub enum CalendarObjectType { } impl CalendarObjectType { - pub fn as_str(&self) -> &'static str { + #[must_use] pub const fn as_str(&self) -> &'static str { match self { - CalendarObjectType::Event => "VEVENT", - CalendarObjectType::Todo => "VTODO", - CalendarObjectType::Journal => "VJOURNAL", + Self::Event => "VEVENT", + Self::Todo => "VTODO", + Self::Journal => "VJOURNAL", } } } @@ -66,9 +66,9 @@ pub enum CalendarObjectComponent { impl From<&CalendarObjectComponent> for CalendarObjectType { fn from(value: &CalendarObjectComponent) -> Self { match value { - CalendarObjectComponent::Event(..) => CalendarObjectType::Event, - CalendarObjectComponent::Todo(..) => CalendarObjectType::Todo, - CalendarObjectComponent::Journal(..) => CalendarObjectType::Journal, + CalendarObjectComponent::Event(..) => Self::Event, + CalendarObjectComponent::Todo(..) => Self::Todo, + CalendarObjectComponent::Journal(..) => Self::Journal, } } } @@ -154,10 +154,10 @@ impl CalendarObject { )); } - if !cal.events.is_empty() as u8 - + !cal.todos.is_empty() as u8 - + !cal.journals.is_empty() as u8 - + !cal.free_busys.is_empty() as u8 + if u8::from(!cal.events.is_empty()) + + u8::from(!cal.todos.is_empty()) + + u8::from(!cal.journals.is_empty()) + + u8::from(!cal.free_busys.is_empty()) != 1 { // https://datatracker.ietf.org/doc/html/rfc4791#section-4.1 @@ -208,15 +208,15 @@ impl CalendarObject { }) } - pub fn get_vtimezones(&self) -> &HashMap { + #[must_use] pub const fn get_vtimezones(&self) -> &HashMap { &self.vtimezones } - pub fn get_data(&self) -> &CalendarObjectComponent { + #[must_use] pub const fn get_data(&self) -> &CalendarObjectComponent { &self.data } - pub fn get_id(&self) -> &str { + #[must_use] pub fn get_id(&self) -> &str { match &self.data { // We've made sure before that the first component exists and all components share the // same UID @@ -226,22 +226,22 @@ impl CalendarObject { } } - pub fn get_etag(&self) -> String { + #[must_use] pub fn get_etag(&self) -> String { let mut hasher = Sha256::new(); hasher.update(self.get_id()); hasher.update(self.get_ics()); format!("\"{:x}\"", hasher.finalize()) } - pub fn get_ics(&self) -> &str { + #[must_use] pub fn get_ics(&self) -> &str { &self.ics } - pub fn get_component_name(&self) -> &str { + #[must_use] pub fn get_component_name(&self) -> &str { self.get_object_type().as_str() } - pub fn get_object_type(&self) -> CalendarObjectType { + #[must_use] pub fn get_object_type(&self) -> CalendarObjectType { (&self.data).into() } @@ -250,7 +250,7 @@ impl CalendarObject { CalendarObjectComponent::Event(main_event, overrides) => Ok(overrides .iter() .chain([main_event].into_iter()) - .map(|event| event.get_dtstart()) + .map(super::event::EventObject::get_dtstart) .collect::, _>>()? .into_iter() .flatten() @@ -264,7 +264,7 @@ impl CalendarObject { CalendarObjectComponent::Event(main_event, overrides) => Ok(overrides .iter() .chain([main_event].into_iter()) - .map(|event| event.get_last_occurence()) + .map(super::event::EventObject::get_last_occurence) .collect::, _>>()? .into_iter() .flatten() diff --git a/crates/ical/src/timestamp.rs b/crates/ical/src/timestamp.rs index 8b0d229..74a9720 100644 --- a/crates/ical/src/timestamp.rs +++ b/crates/ical/src/timestamp.rs @@ -73,7 +73,7 @@ impl From for DateTime { value .as_datetime() .into_owned() - .with_timezone(&value.timezone().to_owned().into()) + .with_timezone(&value.timezone().into()) } } @@ -102,13 +102,13 @@ impl Ord for CalDateTime { impl From> for CalDateTime { fn from(value: DateTime) -> Self { - CalDateTime::DateTime(value.with_timezone(&ICalTimezone::Local)) + Self::DateTime(value.with_timezone(&ICalTimezone::Local)) } } impl From> for CalDateTime { fn from(value: DateTime) -> Self { - CalDateTime::DateTime(value.with_timezone(&ICalTimezone::Olson(chrono_tz::UTC))) + Self::DateTime(value.with_timezone(&ICalTimezone::Olson(chrono_tz::UTC))) } } @@ -158,7 +158,7 @@ impl CalDateTime { Self::parse(prop_value, timezone) } - pub fn format(&self) -> String { + #[must_use] pub fn format(&self) -> String { match self { Self::DateTime(datetime) => match datetime.timezone() { ICalTimezone::Olson(chrono_tz::UTC) => datetime.format(UTC_DATE_TIME).to_string(), @@ -168,25 +168,25 @@ impl CalDateTime { } } - pub fn format_date(&self) -> String { + #[must_use] pub fn format_date(&self) -> String { match self { Self::DateTime(datetime) => datetime.format(LOCAL_DATE).to_string(), Self::Date(date, _) => date.format(LOCAL_DATE).to_string(), } } - pub fn date(&self) -> NaiveDate { + #[must_use] pub fn date(&self) -> NaiveDate { match self { Self::DateTime(datetime) => datetime.date_naive(), Self::Date(date, _) => date.to_owned(), } } - pub fn is_date(&self) -> bool { + #[must_use] pub const fn is_date(&self) -> bool { matches!(&self, Self::Date(_, _)) } - pub fn as_datetime(&self) -> Cow<'_, DateTime> { + #[must_use] pub fn as_datetime(&self) -> Cow<'_, DateTime> { match self { Self::DateTime(datetime) => Cow::Borrowed(datetime), Self::Date(date, tz) => Cow::Owned( @@ -201,14 +201,14 @@ impl CalDateTime { pub fn parse(value: &str, timezone: Option) -> Result { if let Ok(datetime) = NaiveDateTime::parse_from_str(value, LOCAL_DATE_TIME) { if let Some(timezone) = timezone { - return Ok(CalDateTime::DateTime( + return Ok(Self::DateTime( datetime .and_local_timezone(timezone.into()) .earliest() .ok_or(CalDateTimeError::LocalTimeGap)?, )); } - return Ok(CalDateTime::DateTime( + return Ok(Self::DateTime( datetime .and_local_timezone(ICalTimezone::Local) .earliest() @@ -220,17 +220,16 @@ impl CalDateTime { return Ok(datetime.and_utc().into()); } let timezone = timezone - .map(ICalTimezone::Olson) - .unwrap_or(ICalTimezone::Local); + .map_or(ICalTimezone::Local, ICalTimezone::Olson); if let Ok(date) = NaiveDate::parse_from_str(value, LOCAL_DATE) { - return Ok(CalDateTime::Date(date, timezone)); + return Ok(Self::Date(date, timezone)); } if let Ok(date) = NaiveDate::parse_from_str(value, "%Y-%m-%d") { - return Ok(CalDateTime::Date(date, timezone)); + return Ok(Self::Date(date, timezone)); } if let Ok(date) = NaiveDate::parse_from_str(value, "%Y%m%d") { - return Ok(CalDateTime::Date(date, timezone)); + return Ok(Self::Date(date, timezone)); } Err(CalDateTimeError::InvalidDatetimeFormat(value.to_string())) @@ -250,7 +249,7 @@ impl CalDateTime { let day = captures.name("d").unwrap().as_str().parse().ok().unwrap(); return Ok(( - CalDateTime::Date( + Self::Date( NaiveDate::from_ymd_opt(year, month, day) .ok_or(CalDateTimeError::ParseError(value.to_string()))?, ICalTimezone::Local, @@ -261,14 +260,14 @@ impl CalDateTime { Err(CalDateTimeError::InvalidDatetimeFormat(value.to_string())) } - pub fn utc(&self) -> DateTime { + #[must_use] pub fn utc(&self) -> DateTime { self.as_datetime().to_utc() } - pub fn timezone(&self) -> ICalTimezone { + #[must_use] pub fn timezone(&self) -> ICalTimezone { match &self { - CalDateTime::DateTime(datetime) => datetime.timezone(), - CalDateTime::Date(_, tz) => tz.to_owned(), + Self::DateTime(datetime) => datetime.timezone(), + Self::Date(_, tz) => tz.to_owned(), } } } @@ -282,107 +281,107 @@ impl From for DateTime { impl Datelike for CalDateTime { fn year(&self) -> i32 { match &self { - CalDateTime::DateTime(datetime) => datetime.year(), - CalDateTime::Date(date, _) => date.year(), + Self::DateTime(datetime) => datetime.year(), + Self::Date(date, _) => date.year(), } } fn month(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.month(), - CalDateTime::Date(date, _) => date.month(), + Self::DateTime(datetime) => datetime.month(), + Self::Date(date, _) => date.month(), } } fn month0(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.month0(), - CalDateTime::Date(date, _) => date.month0(), + Self::DateTime(datetime) => datetime.month0(), + Self::Date(date, _) => date.month0(), } } fn day(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.day(), - CalDateTime::Date(date, _) => date.day(), + Self::DateTime(datetime) => datetime.day(), + Self::Date(date, _) => date.day(), } } fn day0(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.day0(), - CalDateTime::Date(date, _) => date.day0(), + Self::DateTime(datetime) => datetime.day0(), + Self::Date(date, _) => date.day0(), } } fn ordinal(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.ordinal(), - CalDateTime::Date(date, _) => date.ordinal(), + Self::DateTime(datetime) => datetime.ordinal(), + Self::Date(date, _) => date.ordinal(), } } fn ordinal0(&self) -> u32 { match &self { - CalDateTime::DateTime(datetime) => datetime.ordinal0(), - CalDateTime::Date(date, _) => date.ordinal0(), + Self::DateTime(datetime) => datetime.ordinal0(), + Self::Date(date, _) => date.ordinal0(), } } fn weekday(&self) -> chrono::Weekday { match &self { - CalDateTime::DateTime(datetime) => datetime.weekday(), - CalDateTime::Date(date, _) => date.weekday(), + Self::DateTime(datetime) => datetime.weekday(), + Self::Date(date, _) => date.weekday(), } } fn iso_week(&self) -> chrono::IsoWeek { match &self { - CalDateTime::DateTime(datetime) => datetime.iso_week(), - CalDateTime::Date(date, _) => date.iso_week(), + Self::DateTime(datetime) => datetime.iso_week(), + Self::Date(date, _) => date.iso_week(), } } fn with_year(&self, year: i32) -> Option { match &self { - CalDateTime::DateTime(datetime) => Some(Self::DateTime(datetime.with_year(year)?)), - CalDateTime::Date(date, tz) => Some(Self::Date(date.with_year(year)?, tz.to_owned())), + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_year(year)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_year(year)?, tz.to_owned())), } } fn with_month(&self, month: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => Some(Self::DateTime(datetime.with_month(month)?)), - CalDateTime::Date(date, tz) => Some(Self::Date(date.with_month(month)?, tz.to_owned())), + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_month(month)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_month(month)?, tz.to_owned())), } } fn with_month0(&self, month0: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => Some(Self::DateTime(datetime.with_month0(month0)?)), - CalDateTime::Date(date, tz) => { + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_month0(month0)?)), + Self::Date(date, tz) => { Some(Self::Date(date.with_month0(month0)?, tz.to_owned())) } } } fn with_day(&self, day: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => Some(Self::DateTime(datetime.with_day(day)?)), - CalDateTime::Date(date, tz) => Some(Self::Date(date.with_day(day)?, tz.to_owned())), + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_day(day)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_day(day)?, tz.to_owned())), } } fn with_day0(&self, day0: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => Some(Self::DateTime(datetime.with_day0(day0)?)), - CalDateTime::Date(date, tz) => Some(Self::Date(date.with_day0(day0)?, tz.to_owned())), + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_day0(day0)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_day0(day0)?, tz.to_owned())), } } fn with_ordinal(&self, ordinal: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => { + Self::DateTime(datetime) => { Some(Self::DateTime(datetime.with_ordinal(ordinal)?)) } - CalDateTime::Date(date, tz) => { + Self::Date(date, tz) => { Some(Self::Date(date.with_ordinal(ordinal)?, tz.to_owned())) } } } fn with_ordinal0(&self, ordinal0: u32) -> Option { match &self { - CalDateTime::DateTime(datetime) => { + Self::DateTime(datetime) => { Some(Self::DateTime(datetime.with_ordinal0(ordinal0)?)) } - CalDateTime::Date(date, tz) => { + Self::Date(date, tz) => { Some(Self::Date(date.with_ordinal0(ordinal0)?, tz.to_owned())) } } diff --git a/crates/ical/src/timezone.rs b/crates/ical/src/timezone.rs index 6205ab2..aea5c9e 100644 --- a/crates/ical/src/timezone.rs +++ b/crates/ical/src/timezone.rs @@ -26,7 +26,7 @@ impl From for ICalTimezone { } } -#[derive(Debug, Clone, PartialEq, Display)] +#[derive(Debug, Clone, PartialEq, Eq, Display)] pub enum CalTimezoneOffset { Local(chrono::FixedOffset), Olson(chrono_tz::TzOffset), diff --git a/crates/oidc/src/lib.rs b/crates/oidc/src/lib.rs index b86b463..eb63b0c 100644 --- a/crates/oidc/src/lib.rs +++ b/crates/oidc/src/lib.rs @@ -83,7 +83,7 @@ async fn get_oidc_client( })?; Ok(CoreClient::from_provider_metadata( - provider_metadata.clone(), + provider_metadata, client_id.clone(), client_secret.clone(), ) diff --git a/crates/store/src/addressbook.rs b/crates/store/src/addressbook.rs index 98c332b..120781c 100644 --- a/crates/store/src/addressbook.rs +++ b/crates/store/src/addressbook.rs @@ -14,7 +14,7 @@ pub struct Addressbook { } impl Addressbook { - pub fn format_synctoken(&self) -> String { + #[must_use] pub fn format_synctoken(&self) -> String { format_synctoken(self.synctoken) } } diff --git a/crates/store/src/auth/middleware.rs b/crates/store/src/auth/middleware.rs index eaf6ad9..f8a75b7 100644 --- a/crates/store/src/auth/middleware.rs +++ b/crates/store/src/auth/middleware.rs @@ -23,7 +23,7 @@ impl Clone for AuthenticationLayer { } impl AuthenticationLayer { - pub fn new(auth_provider: Arc) -> Self { + pub const fn new(auth_provider: Arc) -> Self { Self { auth_provider } } } diff --git a/crates/store/src/auth/principal.rs b/crates/store/src/auth/principal.rs index b52ee18..4ca71f7 100644 --- a/crates/store/src/auth/principal.rs +++ b/crates/store/src/auth/principal.rs @@ -35,7 +35,7 @@ impl Principal { /// Returns true if the user is either /// - the principal itself /// - has full access to the prinicpal (is member) - pub fn is_principal(&self, principal: &str) -> bool { + #[must_use] pub fn is_principal(&self, principal: &str) -> bool { if self.id == principal { return true; } diff --git a/crates/store/src/auth/principal_type.rs b/crates/store/src/auth/principal_type.rs index 89bc24e..69a5ca3 100644 --- a/crates/store/src/auth/principal_type.rs +++ b/crates/store/src/auth/principal_type.rs @@ -3,8 +3,8 @@ 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)] +/// +#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, clap::ValueEnum)] #[serde(rename_all = "lowercase")] pub enum PrincipalType { #[default] @@ -36,13 +36,13 @@ impl TryFrom<&str> for PrincipalType { } impl PrincipalType { - pub fn as_str(&self) -> &'static str { + #[must_use] pub const fn as_str(&self) -> &'static str { match self { - PrincipalType::Individual => "INDIVIDUAL", - PrincipalType::Group => "GROUP", - PrincipalType::Resource => "RESOURCE", - PrincipalType::Room => "ROOM", - PrincipalType::Unknown => "UNKNOWN", + Self::Individual => "INDIVIDUAL", + Self::Group => "GROUP", + Self::Resource => "RESOURCE", + Self::Room => "ROOM", + Self::Unknown => "UNKNOWN", } } } diff --git a/crates/store/src/calendar.rs b/crates/store/src/calendar.rs index 54d5721..a8a7567 100644 --- a/crates/store/src/calendar.rs +++ b/crates/store/src/calendar.rs @@ -32,19 +32,19 @@ pub struct Calendar { } impl Calendar { - pub fn format_synctoken(&self) -> String { + #[must_use] pub fn format_synctoken(&self) -> String { format_synctoken(self.synctoken) } - pub fn get_timezone(&self) -> Option { + #[must_use] pub fn get_timezone(&self) -> Option { self.timezone_id .as_ref() .and_then(|tzid| chrono_tz::Tz::from_str(tzid).ok()) } - pub fn get_vtimezone(&self) -> Option<&'static str> { + #[must_use] pub fn get_vtimezone(&self) -> Option<&'static str> { self.timezone_id .as_ref() - .and_then(|tzid| vtimezones_rs::VTIMEZONES.get(tzid).cloned()) + .and_then(|tzid| vtimezones_rs::VTIMEZONES.get(tzid).copied()) } } diff --git a/crates/store/src/contact_birthday_store.rs b/crates/store/src/contact_birthday_store.rs index 246d436..507f328 100644 --- a/crates/store/src/contact_birthday_store.rs +++ b/crates/store/src/contact_birthday_store.rs @@ -8,7 +8,7 @@ use rustical_ical::{AddressObject, CalendarObject, CalendarObjectType}; use sha2::{Digest, Sha256}; use std::{collections::HashMap, sync::Arc}; -pub(crate) const BIRTHDAYS_PREFIX: &str = "_birthdays_"; +pub const BIRTHDAYS_PREFIX: &str = "_birthdays_"; #[derive(Constructor, Clone)] pub struct ContactBirthdayStore(Arc); @@ -43,7 +43,7 @@ fn birthday_calendar(addressbook: Addressbook) -> Calendar { } } -/// Objects are all prefixed with BIRTHDAYS_PREFIX +/// Objects are all prefixed with `BIRTHDAYS_PREFIX` #[async_trait] impl CalendarStore for ContactBirthdayStore { async fn get_calendar( @@ -165,7 +165,7 @@ impl CalendarStore for ContactBirthdayStore { let cal_id = cal_id .strip_prefix(BIRTHDAYS_PREFIX) .ok_or(Error::NotFound)?; - let (addressobject_id, date_type) = object_id.rsplit_once("-").ok_or(Error::NotFound)?; + let (addressobject_id, date_type) = object_id.rsplit_once('-').ok_or(Error::NotFound)?; self.0 .get_object(principal, cal_id, addressobject_id, show_deleted) .await? diff --git a/crates/store/src/error.rs b/crates/store/src/error.rs index f6218d2..5739b1d 100644 --- a/crates/store/src/error.rs +++ b/crates/store/src/error.rs @@ -30,7 +30,7 @@ pub enum Error { } impl Error { - pub fn status_code(&self) -> StatusCode { + #[must_use] pub const fn status_code(&self) -> StatusCode { match self { Self::NotFound => StatusCode::NOT_FOUND, Self::AlreadyExists => StatusCode::CONFLICT, diff --git a/crates/store/src/synctoken.rs b/crates/store/src/synctoken.rs index 67425bf..b7dbcf9 100644 --- a/crates/store/src/synctoken.rs +++ b/crates/store/src/synctoken.rs @@ -1,10 +1,10 @@ const SYNC_NAMESPACE: &str = "github.com/lennart-k/rustical/ns/"; -pub fn format_synctoken(synctoken: i64) -> String { +#[must_use] pub fn format_synctoken(synctoken: i64) -> String { format!("{SYNC_NAMESPACE}{synctoken}") } -pub fn parse_synctoken(synctoken: &str) -> Option { +#[must_use] pub fn parse_synctoken(synctoken: &str) -> Option { if !synctoken.starts_with(SYNC_NAMESPACE) { return None; } diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index 2928f9d..b6897a2 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -138,26 +138,23 @@ impl SqliteAddressbookStore { addressbook_id: &str, use_trashbin: bool, ) -> Result<(), rustical_store::Error> { - match use_trashbin { - true => { - sqlx::query!( - r#"UPDATE addressbooks SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, - principal, addressbook_id - ) - .execute(executor) - .await.map_err(crate::Error::from)?; - } - false => { - sqlx::query!( - r#"DELETE FROM addressbooks WHERE (principal, id) = (?, ?)"#, - principal, - addressbook_id - ) - .execute(executor) - .await - .map_err(crate::Error::from)?; - } - }; + if use_trashbin { + sqlx::query!( + r#"UPDATE addressbooks SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, + principal, addressbook_id + ) + .execute(executor) + .await.map_err(crate::Error::from)?; + } else { + sqlx::query!( + r#"DELETE FROM addressbooks WHERE (principal, id) = (?, ?)"#, + principal, + addressbook_id + ) + .execute(executor) + .await + .map_err(crate::Error::from)?; + } Ok(()) } @@ -208,8 +205,7 @@ impl SqliteAddressbookStore { let new_synctoken = changes .last() - .map(|&Row { synctoken, .. }| synctoken) - .unwrap_or(0); + .map_or(0, |&Row { synctoken, .. }| synctoken); for Row { object_id, .. } in changes { match Self::_get_object(&mut *conn, principal, addressbook_id, &object_id, false).await @@ -259,7 +255,7 @@ impl SqliteAddressbookStore { .fetch_all(executor) .await.map_err(crate::Error::from)? .into_iter() - .map(|row| row.try_into()) + .map(std::convert::TryInto::try_into) .collect() } @@ -325,28 +321,25 @@ impl SqliteAddressbookStore { object_id: &str, use_trashbin: bool, ) -> Result<(), rustical_store::Error> { - match use_trashbin { - true => { - sqlx::query!( - "UPDATE addressobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, addressbook_id, id) = (?, ?, ?)", - principal, - addressbook_id, - object_id - ) - .execute(executor) - .await.map_err(crate::Error::from)?; - } - false => { - sqlx::query!( - "DELETE FROM addressobjects WHERE addressbook_id = ? AND id = ?", - addressbook_id, - object_id - ) - .execute(executor) - .await - .map_err(crate::Error::from)?; - } - }; + if use_trashbin { + sqlx::query!( + "UPDATE addressobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, addressbook_id, id) = (?, ?, ?)", + principal, + addressbook_id, + object_id + ) + .execute(executor) + .await.map_err(crate::Error::from)?; + } else { + sqlx::query!( + "DELETE FROM addressobjects WHERE addressbook_id = ? AND id = ?", + addressbook_id, + object_id + ) + .execute(executor) + .await + .map_err(crate::Error::from)?; + } Ok(()) } @@ -440,7 +433,7 @@ impl AddressbookStore for SqliteAddressbookStore { }) { error!("Push notification about deleted addressbook failed: {err}"); - }; + } Ok(()) } @@ -474,9 +467,9 @@ impl AddressbookStore for SqliteAddressbookStore { let mut deleted_sizes = vec![]; for (size, deleted) in Self::_list_objects(&self.db, principal, addressbook_id).await? { if deleted { - deleted_sizes.push(size) + deleted_sizes.push(size); } else { - sizes.push(size) + sizes.push(size); } } Ok(CollectionMetadata { @@ -521,8 +514,8 @@ impl AddressbookStore for SqliteAddressbookStore { Self::_put_object( &mut *tx, - principal.to_owned(), - addressbook_id.to_owned(), + principal.clone(), + addressbook_id.clone(), object, overwrite, ) @@ -548,7 +541,7 @@ impl AddressbookStore for SqliteAddressbookStore { .push_topic, }) { error!("Push notification about deleted addressbook failed: {err}"); - }; + } Ok(()) } @@ -585,7 +578,7 @@ impl AddressbookStore for SqliteAddressbookStore { .push_topic, }) { error!("Push notification about deleted addressbook failed: {err}"); - }; + } Ok(()) } @@ -619,7 +612,7 @@ impl AddressbookStore for SqliteAddressbookStore { .push_topic, }) { error!("Push notification about deleted addressbook failed: {err}"); - }; + } Ok(()) } diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 8127913..7e0d12b 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -22,7 +22,7 @@ impl TryFrom for CalendarObject { type Error = rustical_store::Error; fn try_from(value: CalendarObjectRow) -> Result { - let object = CalendarObject::from_ics(value.ics)?; + let object = Self::from_ics(value.ics)?; if object.get_id() != value.id { return Err(rustical_store::Error::IcalError( rustical_ical::Error::InvalidData(format!( @@ -213,24 +213,21 @@ impl SqliteCalendarStore { id: &str, use_trashbin: bool, ) -> Result<(), Error> { - match use_trashbin { - true => sqlx::query!( - r#"UPDATE calendars SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, - principal, - id - ) - .execute(executor) - .await - .map_err(crate::Error::from)?, - false => sqlx::query!( - r#"DELETE FROM calendars WHERE (principal, id) = (?, ?)"#, - principal, - id - ) - .execute(executor) - .await - .map_err(crate::Error::from)?, - }; + if use_trashbin { sqlx::query!( + r#"UPDATE calendars SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, + principal, + id + ) + .execute(executor) + .await + .map_err(crate::Error::from)? } else { sqlx::query!( + r#"DELETE FROM calendars WHERE (principal, id) = (?, ?)"#, + principal, + id + ) + .execute(executor) + .await + .map_err(crate::Error::from)? }; Ok(()) } @@ -286,7 +283,7 @@ impl SqliteCalendarStore { .fetch_all(executor) .await.map_err(crate::Error::from)? .into_iter() - .map(|row| row.try_into()) + .map(std::convert::TryInto::try_into) .collect() } @@ -320,7 +317,7 @@ impl SqliteCalendarStore { .await .map_err(crate::Error::from)? .into_iter() - .map(|row| row.try_into()) + .map(std::convert::TryInto::try_into) .collect() } @@ -411,28 +408,25 @@ impl SqliteCalendarStore { id: &str, use_trashbin: bool, ) -> Result<(), Error> { - match use_trashbin { - true => { - sqlx::query!( - "UPDATE calendarobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)", - principal, - cal_id, - id - ) - .execute(executor) - .await.map_err(crate::Error::from)?; - } - false => { - sqlx::query!( - "DELETE FROM calendarobjects WHERE cal_id = ? AND id = ?", - cal_id, - id - ) - .execute(executor) - .await - .map_err(crate::Error::from)?; - } - }; + if use_trashbin { + sqlx::query!( + "UPDATE calendarobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)", + principal, + cal_id, + id + ) + .execute(executor) + .await.map_err(crate::Error::from)?; + } else { + sqlx::query!( + "DELETE FROM calendarobjects WHERE cal_id = ? AND id = ?", + cal_id, + id + ) + .execute(executor) + .await + .map_err(crate::Error::from)?; + } Ok(()) } @@ -484,8 +478,7 @@ impl SqliteCalendarStore { let new_synctoken = changes .last() - .map(|&Row { synctoken, .. }| synctoken) - .unwrap_or(0); + .map_or(0, |&Row { synctoken, .. }| synctoken); for Row { object_id, .. } in changes { match Self::_get_object(&mut *conn, principal, cal_id, &object_id, false).await { @@ -562,7 +555,7 @@ impl CalendarStore for SqliteCalendarStore { }) { error!("Push notification about deleted calendar failed: {err}"); - }; + } Ok(()) } @@ -627,9 +620,9 @@ impl CalendarStore for SqliteCalendarStore { let mut deleted_sizes = vec![]; for (size, deleted) in Self::_list_objects(&self.db, principal, cal_id).await? { if deleted { - deleted_sizes.push(size) + deleted_sizes.push(size); } else { - sizes.push(size) + sizes.push(size); } } Ok(CollectionMetadata { @@ -680,8 +673,8 @@ impl CalendarStore for SqliteCalendarStore { Self::_put_object( &mut *tx, - principal.to_owned(), - cal_id.to_owned(), + principal.clone(), + cal_id.clone(), object, overwrite, ) @@ -706,7 +699,7 @@ impl CalendarStore for SqliteCalendarStore { .push_topic, }) { error!("Push notification about deleted calendar failed: {err}"); - }; + } Ok(()) } @@ -731,7 +724,7 @@ impl CalendarStore for SqliteCalendarStore { topic: self.get_calendar(principal, cal_id, true).await?.push_topic, }) { error!("Push notification about deleted calendar failed: {err}"); - }; + } Ok(()) } @@ -756,7 +749,7 @@ impl CalendarStore for SqliteCalendarStore { topic: self.get_calendar(principal, cal_id, true).await?.push_topic, }) { error!("Push notification about deleted calendar failed: {err}"); - }; + } Ok(()) } diff --git a/crates/store_sqlite/src/error.rs b/crates/store_sqlite/src/error.rs index 3c55fd4..38e2af8 100644 --- a/crates/store_sqlite/src/error.rs +++ b/crates/store_sqlite/src/error.rs @@ -15,16 +15,16 @@ pub enum Error { impl From for Error { fn from(value: sqlx::Error) -> Self { match value { - sqlx::Error::RowNotFound => Error::StoreError(rustical_store::Error::NotFound), + sqlx::Error::RowNotFound => Self::StoreError(rustical_store::Error::NotFound), sqlx::Error::Database(err) => { if err.is_unique_violation() { warn!("{err:?}"); - Error::StoreError(rustical_store::Error::AlreadyExists) + Self::StoreError(rustical_store::Error::AlreadyExists) } else { - Error::SqlxError(sqlx::Error::Database(err)) + Self::SqlxError(sqlx::Error::Database(err)) } } - err => Error::SqlxError(err), + err => Self::SqlxError(err), } } } diff --git a/crates/store_sqlite/src/lib.rs b/crates/store_sqlite/src/lib.rs index eb0e0c6..fe94488 100644 --- a/crates/store_sqlite/src/lib.rs +++ b/crates/store_sqlite/src/lib.rs @@ -26,7 +26,7 @@ pub struct SqliteStore { } impl SqliteStore { - pub fn new(db: SqlitePool) -> Self { + #[must_use] pub const fn new(db: SqlitePool) -> Self { Self { db } } } diff --git a/crates/store_sqlite/src/principal_store.rs b/crates/store_sqlite/src/principal_store.rs index 1259f5e..f774fe4 100644 --- a/crates/store_sqlite/src/principal_store.rs +++ b/crates/store_sqlite/src/principal_store.rs @@ -25,7 +25,7 @@ impl TryFrom for Principal { type Error = Error; fn try_from(value: PrincipalRow) -> Result { - Ok(Principal { + Ok(Self { id: value.id, displayname: value.displayname, password: value.password_hash.map(Secret::from), diff --git a/crates/xml/src/de.rs b/crates/xml/src/de.rs index 458ab69..25c12a8 100644 --- a/crates/xml/src/de.rs +++ b/crates/xml/src/de.rs @@ -62,13 +62,13 @@ impl XmlDocument for T { format!("{root_ns:?}"), Self::root_tag().to_owned(), )); - }; + } return Self::deserialize(&mut reader, &start, empty); } Event::Eof => return Err(XmlError::Eof), _ => return Err(XmlError::UnsupportedEvent("unknown, todo")), - }; + } } } } @@ -88,7 +88,7 @@ impl XmlDeserialize for () { Event::End(e) if e.name() == start.name() => return Ok(()), Event::Eof => return Err(XmlError::Eof), _ => {} - }; + } } } } diff --git a/crates/xml/src/namespace.rs b/crates/xml/src/namespace.rs index c3a97df..40b6a67 100644 --- a/crates/xml/src/namespace.rs +++ b/crates/xml/src/namespace.rs @@ -1,6 +1,6 @@ use quick_xml::name::Namespace; -#[derive(Debug, Clone, Default, PartialEq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct NamespaceOwned(pub Vec); impl<'a> From> for NamespaceOwned { @@ -28,7 +28,7 @@ impl<'a> From<&'a Namespace<'a>> for NamespaceOwned { } impl NamespaceOwned { - pub fn as_ref(&self) -> Namespace<'_> { + #[must_use] pub fn as_ref(&self) -> Namespace<'_> { Namespace(&self.0) } } diff --git a/crates/xml/src/se.rs b/crates/xml/src/se.rs index 7ef9fff..ab13622 100644 --- a/crates/xml/src/se.rs +++ b/crates/xml/src/se.rs @@ -65,13 +65,12 @@ impl XmlSerialize for () { writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { let prefix = ns - .map(|ns| namespaces.get(&ns)) - .unwrap_or(None) + .and_then(|ns| namespaces.get(&ns)) .map(|prefix| { - if !prefix.is_empty() { - [*prefix, ":"].concat() - } else { + if prefix.is_empty() { String::new() + } else { + [*prefix, ":"].concat() } }); let has_prefix = prefix.is_some(); diff --git a/crates/xml/src/unparsed.rs b/crates/xml/src/unparsed.rs index bdb371e..37d0708 100644 --- a/crates/xml/src/unparsed.rs +++ b/crates/xml/src/unparsed.rs @@ -5,11 +5,11 @@ use quick_xml::events::BytesStart; use crate::{XmlDeserialize, XmlError}; // TODO: actually implement -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Unparsed(BytesStart<'static>); impl Unparsed { - pub fn tag_name(&self) -> String { + #[must_use] pub fn tag_name(&self) -> String { // TODO: respect namespace? String::from_utf8_lossy(self.0.local_name().as_ref()).to_string() } diff --git a/crates/xml/src/value.rs b/crates/xml/src/value.rs index cfc9b9a..23d938d 100644 --- a/crates/xml/src/value.rs +++ b/crates/xml/src/value.rs @@ -60,7 +60,7 @@ impl_value_parse!(usize); impl ValueSerialize for &str { fn serialize(&self) -> String { - self.to_string() + (*self).to_string() } } @@ -98,7 +98,7 @@ impl XmlDeserialize for T { Event::End(_) => break, Event::Eof => return Err(XmlError::Eof), _ => return Err(XmlError::UnsupportedEvent("todo")), - }; + } } } @@ -115,13 +115,12 @@ impl XmlSerialize for T { writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { let prefix = ns - .map(|ns| namespaces.get(&ns)) - .unwrap_or(None) + .and_then(|ns| namespaces.get(&ns)) .map(|prefix| { - if !prefix.is_empty() { - [*prefix, ":"].concat() - } else { + if prefix.is_empty() { String::new() + } else { + [*prefix, ":"].concat() } }); let has_prefix = prefix.is_some(); diff --git a/src/app.rs b/src/app.rs index 24ac237..08e5bfd 100644 --- a/src/app.rs +++ b/src/app.rs @@ -43,7 +43,7 @@ pub fn make_app( ) -> Router<()> { let birthday_store = Arc::new(ContactBirthdayStore::new(addr_store.clone())); let combined_cal_store = - Arc::new(CombinedCalendarStore::new(cal_store.clone()).with_store(birthday_store)); + Arc::new(CombinedCalendarStore::new(cal_store).with_store(birthday_store)); let mut router = Router::new() .merge(caldav_router( @@ -104,24 +104,19 @@ pub fn make_app( router = router.merge(frontend_router( "/frontend", auth_provider.clone(), - combined_cal_store.clone(), - addr_store.clone(), + combined_cal_store, + addr_store, frontend_config, oidc_config, )); } if nextcloud_login_config.enabled { - router = router.nest( - "/index.php/login/v2", - nextcloud_login_router(auth_provider.clone()), - ); + router = router.nest("/index.php/login/v2", nextcloud_login_router(auth_provider)); } if dav_push_enabled { - router = router.merge(rustical_dav_push::subscription_service( - subscription_store.clone(), - )); + router = router.merge(rustical_dav_push::subscription_service(subscription_store)); } router @@ -178,11 +173,11 @@ pub fn make_app( tracing::error!("client error"); } } - }; + } }) .on_failure( |_error: ServerErrorsFailureClass, _latency: Duration, _span: &Span| { - tracing::error!("something went wrong") + tracing::error!("something went wrong"); }, ), ) diff --git a/src/commands/membership.rs b/src/commands/membership.rs index 5447e63..8e893b3 100644 --- a/src/commands/membership.rs +++ b/src/commands/membership.rs @@ -38,9 +38,9 @@ pub async fn handle_membership_command( MembershipArgs { command }: MembershipArgs, ) -> anyhow::Result<()> { let id = match &command { - MembershipCommand::Assign(AssignArgs { id, .. }) => id, - MembershipCommand::Remove(RemoveArgs { id, .. }) => id, - MembershipCommand::List(ListArgs { id }) => id, + MembershipCommand::Assign(AssignArgs { id, .. }) + | MembershipCommand::Remove(RemoveArgs { id, .. }) + | MembershipCommand::List(ListArgs { id }) => id, }; match &command { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 47bc2f3..7dd5ecd 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,5 +1,6 @@ use crate::config::{ - Config, DataStoreConfig, DavPushConfig, HttpConfig, SqliteDataStoreConfig, TracingConfig, + Config, DataStoreConfig, DavPushConfig, HttpConfig, NextcloudLoginConfig, + SqliteDataStoreConfig, TracingConfig, }; use clap::Parser; use rustical_frontend::FrontendConfig; @@ -23,7 +24,7 @@ pub fn cmd_gen_config(_args: GenConfigArgs) -> anyhow::Result<()> { }, oidc: None, dav_push: DavPushConfig::default(), - nextcloud_login: Default::default(), + nextcloud_login: NextcloudLoginConfig::default(), }; let generated_config = toml::to_string(&config)?; println!("{generated_config}"); diff --git a/src/commands/principals.rs b/src/commands/principals.rs index 88e41e2..70d8aa8 100644 --- a/src/commands/principals.rs +++ b/src/commands/principals.rs @@ -140,7 +140,7 @@ pub async fn cmd_principals(args: PrincipalsArgs) -> anyhow::Result<()> { .unwrap() .to_string() .into(), - ) + ); } if name.is_some() { principal.displayname = name; @@ -152,7 +152,7 @@ pub async fn cmd_principals(args: PrincipalsArgs) -> anyhow::Result<()> { println!("Principal {id} updated"); } Command::Membership(args) => { - handle_membership_command(principal_store.as_ref(), args).await? + handle_membership_command(principal_store.as_ref(), args).await?; } } Ok(()) diff --git a/src/config.rs b/src/config.rs index 0fe6a2b..f0bbbb7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,7 +41,7 @@ pub struct TracingConfig { pub opentelemetry: bool, } -fn default_true() -> bool { +const fn default_true() -> bool { true } diff --git a/src/main.rs b/src/main.rs index ace4304..5459874 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,7 +66,7 @@ async fn get_data_stores( 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())); + let principal_store = Arc::new(SqlitePrincipalStore::new(db)); ( addressbook_store, cal_store, @@ -128,7 +128,7 @@ async fn main() -> Result<()> { let listener = tokio::net::TcpListener::bind(&address).await?; tasks.push(tokio::spawn(async move { info!("RustiCal serving on http://{address}"); - axum::serve(listener, app).await.unwrap() + axum::serve(listener, app).await.unwrap(); })); for task in tasks { From 86cf490fa980ab48bc05f0d7cfa6335c2e1676b8 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:12:21 +0100 Subject: [PATCH 03/15] Lots of clippy appeasement --- Cargo.lock | 2 - Cargo.toml | 1 - crates/caldav/src/calendar/methods/get.rs | 23 ++----- .../caldav/src/calendar/methods/mkcalendar.rs | 31 ++++----- crates/caldav/src/calendar/methods/post.rs | 3 +- .../methods/report/calendar_multiget.rs | 2 - .../methods/report/calendar_query/elements.rs | 14 ++-- .../methods/report/calendar_query/mod.rs | 6 +- .../caldav/src/calendar/methods/report/mod.rs | 12 ++-- crates/caldav/src/calendar/resource.rs | 64 +++++++++---------- crates/caldav/src/calendar_object/methods.rs | 2 +- crates/caldav/src/calendar_object/prop.rs | 2 +- crates/caldav/src/calendar_object/resource.rs | 5 +- crates/caldav/src/calendar_object/service.rs | 9 ++- crates/caldav/src/error.rs | 6 +- crates/caldav/src/lib.rs | 1 + crates/caldav/src/principal/prop.rs | 2 +- crates/carddav/src/address_object/prop.rs | 2 +- crates/carddav/src/address_object/service.rs | 9 ++- .../carddav/src/addressbook/methods/mkcol.rs | 2 +- .../carddav/src/addressbook/methods/post.rs | 3 +- .../methods/report/addressbook_multiget.rs | 2 - .../src/addressbook/methods/report/mod.rs | 10 +-- crates/carddav/src/addressbook/prop.rs | 4 +- crates/carddav/src/addressbook/resource.rs | 18 ++++-- crates/carddav/src/error.rs | 6 +- crates/carddav/src/lib.rs | 18 ++---- crates/carddav/src/principal/prop.rs | 2 +- crates/dav/src/error.rs | 6 +- crates/dav/src/extensions/common.rs | 8 +-- crates/dav/src/header/depth.rs | 11 ++-- crates/dav/src/header/overwrite.rs | 11 ++-- crates/dav/src/lib.rs | 1 + crates/dav/src/privileges.rs | 21 ++++-- crates/dav/src/resource/axum_methods.rs | 24 ++++--- crates/dav/src/resource/mod.rs | 39 +++++------ crates/dav/src/resource/resource_service.rs | 5 +- crates/dav/src/xml/href.rs | 3 +- crates/dav/src/xml/multistatus.rs | 2 + crates/dav/src/xml/propfind.rs | 2 +- crates/dav/src/xml/report_set.rs | 3 +- crates/dav/src/xml/resourcetype.rs | 2 +- crates/dav/src/xml/sync_collection.rs | 6 +- crates/dav/src/xml/tag_list.rs | 16 ++--- crates/dav_push/src/extension.rs | 4 +- crates/dav_push/src/lib.rs | 2 + crates/dav_push/src/prop.rs | 6 +- crates/dav_push/src/register.rs | 10 +-- crates/frontend/src/assets.rs | 6 +- crates/frontend/src/lib.rs | 2 +- crates/frontend/src/nextcloud_login/routes.rs | 31 +++++---- crates/frontend/src/oidc_user_store.rs | 7 +- crates/frontend/src/routes/addressbook.rs | 8 +-- crates/frontend/src/routes/calendar.rs | 8 +-- crates/frontend/src/routes/user.rs | 33 +--------- crates/ical/Cargo.toml | 1 - crates/ical/src/address_object.rs | 28 ++++---- crates/ical/src/error.rs | 8 ++- crates/ical/src/icalendar/event.rs | 27 ++++---- crates/ical/src/icalendar/object.rs | 28 +++++--- crates/ical/src/lib.rs | 1 + crates/ical/src/timestamp.rs | 59 ++++++++--------- crates/oidc/src/lib.rs | 1 + crates/store/Cargo.toml | 1 - crates/store/src/addressbook.rs | 3 +- crates/store/src/auth/middleware.rs | 4 +- crates/store/src/auth/principal.rs | 3 +- crates/store/src/auth/principal_type.rs | 3 +- crates/store/src/calendar.rs | 9 ++- crates/store/src/combined_calendar_store.rs | 4 +- crates/store/src/error.rs | 3 +- crates/store/src/synctoken.rs | 6 +- crates/store_sqlite/src/addressbook_store.rs | 10 +-- crates/store_sqlite/src/calendar_store.rs | 38 +++++------ crates/store_sqlite/src/lib.rs | 4 +- crates/store_sqlite/src/principal_store.rs | 5 +- crates/xml/src/de.rs | 8 +-- crates/xml/src/lib.rs | 1 + crates/xml/src/namespace.rs | 3 +- crates/xml/src/se.rs | 23 +++---- crates/xml/src/unparsed.rs | 3 +- crates/xml/src/value.rs | 16 ++--- src/app.rs | 8 ++- src/main.rs | 2 +- 84 files changed, 413 insertions(+), 435 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73a01a2..46c9a53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3194,7 +3194,6 @@ dependencies = [ "chrono-tz", "derive_more", "ical", - "lazy_static", "regex", "rrule", "rustical_xml", @@ -3234,7 +3233,6 @@ dependencies = [ "headers", "http", "ical", - "lazy_static", "regex", "rrule", "rstest", diff --git a/Cargo.toml b/Cargo.toml index e6b2c9b..b0a916c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ pbkdf2 = { version = "0.12", features = ["simple"] } rand_core = { version = "0.9", features = ["std"] } chrono = { version = "0.4", features = ["serde"] } regex = "1.10" -lazy_static = "1.5" rstest = "0.26" rstest_reuse = "0.7" sha2 = "0.10" diff --git a/crates/caldav/src/calendar/methods/get.rs b/crates/caldav/src/calendar/methods/get.rs index ef5d955..2cbe928 100644 --- a/crates/caldav/src/calendar/methods/get.rs +++ b/crates/caldav/src/calendar/methods/get.rs @@ -32,7 +32,6 @@ pub async fn route_get( return Err(crate::Error::Unauthorized); } - let mut timezones = HashMap::new(); let mut vtimezones = HashMap::new(); let objects = cal_store.get_objects(&principal, &calendar_id).await?; @@ -64,31 +63,23 @@ pub async fn route_get( for object in &objects { vtimezones.extend(object.get_vtimezones()); match object.get_data() { - CalendarObjectComponent::Event( - EventObject { - event, - timezones: object_timezones, - .. - }, - overrides, - ) => { - timezones.extend(object_timezones); + CalendarObjectComponent::Event(EventObject { event, .. }, overrides) => { ical_calendar_builder = ical_calendar_builder.add_event(event.clone()); - for _override in overrides { + for ev_override in overrides { ical_calendar_builder = - ical_calendar_builder.add_event(_override.event.clone()); + ical_calendar_builder.add_event(ev_override.event.clone()); } } CalendarObjectComponent::Todo(todo, overrides) => { ical_calendar_builder = ical_calendar_builder.add_todo(todo.clone()); - for _override in overrides { - ical_calendar_builder = ical_calendar_builder.add_todo(_override.clone()); + for ev_override in overrides { + ical_calendar_builder = ical_calendar_builder.add_todo(ev_override.clone()); } } CalendarObjectComponent::Journal(journal, overrides) => { ical_calendar_builder = ical_calendar_builder.add_journal(journal.clone()); - for _override in overrides { - ical_calendar_builder = ical_calendar_builder.add_journal(_override.clone()); + for ev_override in overrides { + ical_calendar_builder = ical_calendar_builder.add_journal(ev_override.clone()); } } } diff --git a/crates/caldav/src/calendar/methods/mkcalendar.rs b/crates/caldav/src/calendar/methods/mkcalendar.rs index 0ec65c9..2d65e0c 100644 --- a/crates/caldav/src/calendar/methods/mkcalendar.rs +++ b/crates/caldav/src/calendar/methods/mkcalendar.rs @@ -89,17 +89,12 @@ pub async fn route_mkcalendar( // TODO: Proper error (calendar-timezone precondition) let calendar = IcalParser::new(tz.as_bytes()) .next() - .ok_or(rustical_dav::Error::BadRequest( - "No timezone data provided".to_owned(), - ))? + .ok_or_else(|| rustical_dav::Error::BadRequest("No timezone data provided".to_owned()))? .map_err(|_| rustical_dav::Error::BadRequest("No timezone data provided".to_owned()))?; - let timezone = calendar - .timezones - .first() - .ok_or(rustical_dav::Error::BadRequest( - "No timezone data provided".to_owned(), - ))?; + let timezone = calendar.timezones.first().ok_or_else(|| { + rustical_dav::Error::BadRequest("No timezone data provided".to_owned()) + })?; let timezone: chrono_tz::Tz = timezone .try_into() .map_err(|_| rustical_dav::Error::BadRequest("No timezone data provided".to_owned()))?; @@ -123,14 +118,16 @@ pub async fn route_mkcalendar( synctoken: 0, subscription_url: request.source.map(|href| href.href), push_topic: uuid::Uuid::new_v4().to_string(), - components: request - .supported_calendar_component_set - .map(Into::into) - .unwrap_or(vec![ - CalendarObjectType::Event, - CalendarObjectType::Todo, - CalendarObjectType::Journal, - ]), + components: request.supported_calendar_component_set.map_or_else( + || { + vec![ + CalendarObjectType::Event, + CalendarObjectType::Todo, + CalendarObjectType::Journal, + ] + }, + Into::into, + ), }; cal_store.insert_calendar(calendar).await?; diff --git a/crates/caldav/src/calendar/methods/post.rs b/crates/caldav/src/calendar/methods/post.rs index 014d10a..d27e829 100644 --- a/crates/caldav/src/calendar/methods/post.rs +++ b/crates/caldav/src/calendar/methods/post.rs @@ -53,7 +53,8 @@ pub async fn route_post( push_resource: request .subscription .web_push_subscription - .push_resource.clone(), + .push_resource + .clone(), topic: calendar_resource.cal.push_topic, expiration: expires.naive_local(), public_key: request diff --git a/crates/caldav/src/calendar/methods/report/calendar_multiget.rs b/crates/caldav/src/calendar/methods/report/calendar_multiget.rs index dd5af84..ae5277a 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_multiget.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_multiget.rs @@ -36,11 +36,9 @@ pub async fn get_objects_calendar_multiget( } } else { not_found.push(href.to_owned()); - continue; } } else { not_found.push(href.to_owned()); - continue; } } diff --git a/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs b/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs index 64ce9c4..37a8648 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_query/elements.rs @@ -36,7 +36,7 @@ pub struct TextMatchElement { pub(crate) negate_condition: Option, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[allow(dead_code)] // https://www.rfc-editor.org/rfc/rfc4791#section-9.7.2 pub struct PropFilterElement { @@ -76,7 +76,7 @@ impl CompFilterElement { let comp_vcal = self.name == "VCALENDAR"; match (self.is_not_defined, comp_vcal) { // Client wants VCALENDAR to not exist but we are a VCALENDAR - (Some(()), true) => return false, + (Some(()), true) | // Client is asking for something different than a vcalendar (None, false) => return false, _ => {} @@ -106,7 +106,7 @@ impl CompFilterElement { let comp_name_matches = self.name == cal_object.get_component_name(); match (self.is_not_defined, comp_name_matches) { // Client wants VCALENDAR to not exist but we are a VCALENDAR - (Some(()), true) => return false, + (Some(()), true) | // Client is asking for something different than a vcalendar (None, false) => return false, _ => {} @@ -164,7 +164,7 @@ impl From<&FilterElement> for CalendarQuery { }; } } - Default::default() + Self::default() } } @@ -184,10 +184,6 @@ pub struct CalendarQueryRequest { impl From<&CalendarQueryRequest> for CalendarQuery { fn from(value: &CalendarQueryRequest) -> Self { - value - .filter - .as_ref() - .map(Self::from) - .unwrap_or_default() + value.filter.as_ref().map(Self::from).unwrap_or_default() } } diff --git a/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs b/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs index 34d4835..7490fc7 100644 --- a/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs +++ b/crates/caldav/src/calendar/methods/report/calendar_query/mod.rs @@ -33,7 +33,7 @@ mod tests { PropFilterElement, TextMatchElement, }, }, - calendar_object::{CalendarObjectPropName, CalendarObjectPropWrapperName}, + calendar_object::{CalendarData, CalendarObjectPropName, CalendarObjectPropWrapperName}, }; #[test] @@ -76,7 +76,7 @@ mod tests { CalendarObjectPropName::Getetag, ), CalendarObjectPropWrapperName::CalendarObject( - CalendarObjectPropName::CalendarData(Default::default()) + CalendarObjectPropName::CalendarData(CalendarData::default()) ), ], vec![] @@ -115,6 +115,6 @@ mod tests { timezone: None, timezone_id: None } - ) + ); } } diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs index 5952aea..2703f01 100644 --- a/crates/caldav/src/calendar/methods/report/mod.rs +++ b/crates/caldav/src/calendar/methods/report/mod.rs @@ -43,9 +43,9 @@ pub(crate) enum ReportRequest { impl ReportRequest { const fn props(&self) -> &PropfindType { match &self { - Self::CalendarMultiget(CalendarMultigetRequest { prop, .. }) => prop, - Self::CalendarQuery(CalendarQueryRequest { prop, .. }) => prop, - Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, + Self::CalendarMultiget(CalendarMultigetRequest { prop, .. }) + | Self::CalendarQuery(CalendarQueryRequest { prop, .. }) + | Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, } } } @@ -184,7 +184,7 @@ mod tests { "/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned() ] }) - ) + ); } #[test] @@ -241,7 +241,7 @@ mod tests { timezone: None, timezone_id: None, }) - ) + ); } #[test] @@ -269,6 +269,6 @@ mod tests { "/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned() ] }) - ) + ); } } diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 785ca77..bec5de3 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -18,7 +18,7 @@ use rustical_xml::{EnumVariants, PropName}; use rustical_xml::{XmlDeserialize, XmlSerialize}; use serde::Deserialize; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "CalendarPropName")] pub enum CalendarProp { // CalDAV (RFC 4791) @@ -54,7 +54,7 @@ pub enum CalendarProp { MaxDateTime(String), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "CalendarPropWrapperName", untagged)] pub enum CalendarPropWrapper { Calendar(CalendarProp), @@ -135,7 +135,9 @@ impl Resource for CalendarResource { } CalendarPropName::CalendarTimezone => { CalendarProp::CalendarTimezone(self.cal.timezone_id.as_ref().and_then(|tzid| { - vtimezones_rs::VTIMEZONES.get(tzid).map(|tz| (*tz).to_string()) + vtimezones_rs::VTIMEZONES + .get(tzid) + .map(|tz| (*tz).to_string()) })) } // chrono_tz uses the IANA database @@ -154,13 +156,13 @@ impl Resource for CalendarResource { CalendarPropName::SupportedCalendarData => { CalendarProp::SupportedCalendarData(SupportedCalendarData::default()) } - CalendarPropName::MaxResourceSize => CalendarProp::MaxResourceSize(10000000), + CalendarPropName::MaxResourceSize => CalendarProp::MaxResourceSize(10_000_000), CalendarPropName::SupportedReportSet => { CalendarProp::SupportedReportSet(SupportedReportSet::all()) } - CalendarPropName::Source => CalendarProp::Source( - self.cal.subscription_url.clone().map(HrefElement::from), - ), + CalendarPropName::Source => { + CalendarProp::Source(self.cal.subscription_url.clone().map(HrefElement::from)) + } CalendarPropName::MinDateTime => { CalendarProp::MinDateTime(CalDateTime::from(DateTime::::MIN_UTC).format()) } @@ -199,22 +201,20 @@ impl Resource for CalendarResource { // TODO: Proper error (calendar-timezone precondition) let calendar = IcalParser::new(tz.as_bytes()) .next() - .ok_or(rustical_dav::Error::BadRequest( - "No timezone data provided".to_owned(), - ))? + .ok_or_else(|| { + rustical_dav::Error::BadRequest( + "No timezone data provided".to_owned(), + ) + })? .map_err(|_| { rustical_dav::Error::BadRequest( "No timezone data provided".to_owned(), ) })?; - let timezone = - calendar - .timezones - .first() - .ok_or(rustical_dav::Error::BadRequest( - "No timezone data provided".to_owned(), - ))?; + let timezone = calendar.timezones.first().ok_or_else(|| { + rustical_dav::Error::BadRequest("No timezone data provided".to_owned()) + })?; let timezone: chrono_tz::Tz = timezone.try_into().map_err(|_| { rustical_dav::Error::BadRequest("No timezone data provided".to_owned()) })?; @@ -223,7 +223,6 @@ impl Resource for CalendarResource { } Ok(()) } - CalendarProp::TimezoneServiceSet(_) => Err(rustical_dav::Error::PropReadOnly), CalendarProp::CalendarTimezoneId(timezone_id) => { if let Some(tzid) = &timezone_id && !vtimezones_rs::VTIMEZONES.contains_key(tzid) @@ -243,13 +242,13 @@ impl Resource for CalendarResource { self.cal.components = comp_set.into(); Ok(()) } - CalendarProp::SupportedCalendarData(_) => Err(rustical_dav::Error::PropReadOnly), - CalendarProp::MaxResourceSize(_) => Err(rustical_dav::Error::PropReadOnly), - CalendarProp::SupportedReportSet(_) => Err(rustical_dav::Error::PropReadOnly), - // Converting between a calendar subscription calendar and a normal one would be weird - CalendarProp::Source(_) => Err(rustical_dav::Error::PropReadOnly), - CalendarProp::MinDateTime(_) => Err(rustical_dav::Error::PropReadOnly), - CalendarProp::MaxDateTime(_) => Err(rustical_dav::Error::PropReadOnly), + CalendarProp::TimezoneServiceSet(_) + | CalendarProp::SupportedCalendarData(_) + | CalendarProp::MaxResourceSize(_) + | CalendarProp::SupportedReportSet(_) + | CalendarProp::Source(_) + | CalendarProp::MinDateTime(_) + | CalendarProp::MaxDateTime(_) => Err(rustical_dav::Error::PropReadOnly), }, CalendarPropWrapper::SyncToken(prop) => SyncTokenExtension::set_prop(self, prop), CalendarPropWrapper::DavPush(prop) => DavPushExtension::set_prop(self, prop), @@ -275,7 +274,6 @@ impl Resource for CalendarResource { self.cal.timezone_id = None; Ok(()) } - CalendarPropName::TimezoneServiceSet => Err(rustical_dav::Error::PropReadOnly), CalendarPropName::CalendarOrder => { self.cal.meta.order = 0; Ok(()) @@ -283,13 +281,13 @@ impl Resource for CalendarResource { CalendarPropName::SupportedCalendarComponentSet => { Err(rustical_dav::Error::PropReadOnly) } - CalendarPropName::SupportedCalendarData => Err(rustical_dav::Error::PropReadOnly), - CalendarPropName::MaxResourceSize => Err(rustical_dav::Error::PropReadOnly), - CalendarPropName::SupportedReportSet => Err(rustical_dav::Error::PropReadOnly), - // Converting a calendar subscription calendar into a normal one would be weird - CalendarPropName::Source => Err(rustical_dav::Error::PropReadOnly), - CalendarPropName::MinDateTime => Err(rustical_dav::Error::PropReadOnly), - CalendarPropName::MaxDateTime => Err(rustical_dav::Error::PropReadOnly), + CalendarPropName::TimezoneServiceSet + | CalendarPropName::SupportedCalendarData + | CalendarPropName::MaxResourceSize + | CalendarPropName::SupportedReportSet + | CalendarPropName::Source + | CalendarPropName::MinDateTime + | CalendarPropName::MaxDateTime => Err(rustical_dav::Error::PropReadOnly), }, CalendarPropWrapperName::SyncToken(prop) => SyncTokenExtension::remove_prop(self, prop), CalendarPropWrapperName::DavPush(prop) => DavPushExtension::remove_prop(self, prop), diff --git a/crates/caldav/src/calendar_object/methods.rs b/crates/caldav/src/calendar_object/methods.rs index 1053076..510b1ed 100644 --- a/crates/caldav/src/calendar_object/methods.rs +++ b/crates/caldav/src/calendar_object/methods.rs @@ -78,7 +78,7 @@ pub async fn put_event( true }; - let object = if let Ok(obj) = CalendarObject::from_ics(body.clone()) { obj } else { + let Ok(object) = CalendarObject::from_ics(body.clone()) else { debug!("invalid calendar data:\n{body}"); return Err(Error::PreconditionFailed(Precondition::ValidCalendarData)); }; diff --git a/crates/caldav/src/calendar_object/prop.rs b/crates/caldav/src/calendar_object/prop.rs index 0922e6d..bea5c68 100644 --- a/crates/caldav/src/calendar_object/prop.rs +++ b/crates/caldav/src/calendar_object/prop.rs @@ -17,7 +17,7 @@ pub enum CalendarObjectProp { CalendarData(String), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "CalendarObjectPropWrapperName", untagged)] pub enum CalendarObjectPropWrapper { CalendarObject(CalendarObjectProp), diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index cd3690f..15af050 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -1,4 +1,7 @@ -use super::prop::{CalendarObjectPropWrapper, CalendarObjectPropWrapperName, CalendarObjectPropName, CalendarObjectProp, CalendarData}; +use super::prop::{ + CalendarData, CalendarObjectProp, CalendarObjectPropName, CalendarObjectPropWrapper, + CalendarObjectPropWrapperName, +}; use crate::Error; use derive_more::derive::{From, Into}; use rustical_dav::{ diff --git a/crates/caldav/src/calendar_object/service.rs b/crates/caldav/src/calendar_object/service.rs index f6527c8..8a63e12 100644 --- a/crates/caldav/src/calendar_object/service.rs +++ b/crates/caldav/src/calendar_object/service.rs @@ -106,9 +106,8 @@ where D: Deserializer<'de>, { let name: String = Deserialize::deserialize(deserializer)?; - if let Some(object_id) = name.strip_suffix(".ics") { - Ok(object_id.to_owned()) - } else { - Err(serde::de::Error::custom("Missing .ics extension")) - } + name.strip_suffix(".ics").map_or_else( + || Err(serde::de::Error::custom("Missing .ics extension")), + |object_id| Ok(object_id.to_owned()), + ) } diff --git a/crates/caldav/src/error.rs b/crates/caldav/src/error.rs index a3a56c5..790646f 100644 --- a/crates/caldav/src/error.rs +++ b/crates/caldav/src/error.rs @@ -62,7 +62,8 @@ pub enum Error { } impl Error { - #[must_use] pub fn status_code(&self) -> StatusCode { + #[must_use] + pub fn status_code(&self) -> StatusCode { match self { Self::StoreError(err) => match err { rustical_store::Error::NotFound => StatusCode::NOT_FOUND, @@ -70,12 +71,11 @@ impl Error { rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, _ => StatusCode::INTERNAL_SERVER_ERROR, }, - Self::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::DavError(err) => StatusCode::try_from(err.status_code().as_u16()) .expect("Just converting between versions"), Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, - Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, + Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Self::NotFound => StatusCode::NOT_FOUND, Self::IcalError(err) => err.status_code(), Self::PreconditionFailed(_err) => StatusCode::PRECONDITION_FAILED, diff --git a/crates/caldav/src/lib.rs b/crates/caldav/src/lib.rs index 9db5f27..991dfc8 100644 --- a/crates/caldav/src/lib.rs +++ b/crates/caldav/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] use axum::{Extension, Router}; use derive_more::Constructor; use principal::PrincipalResourceService; diff --git a/crates/caldav/src/principal/prop.rs b/crates/caldav/src/principal/prop.rs index 6285d8b..5052819 100644 --- a/crates/caldav/src/principal/prop.rs +++ b/crates/caldav/src/principal/prop.rs @@ -37,7 +37,7 @@ pub enum PrincipalProp { #[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] pub Vec); -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)] pub enum PrincipalPropWrapper { Principal(PrincipalProp), diff --git a/crates/carddav/src/address_object/prop.rs b/crates/carddav/src/address_object/prop.rs index 0a33f5e..6451902 100644 --- a/crates/carddav/src/address_object/prop.rs +++ b/crates/carddav/src/address_object/prop.rs @@ -15,7 +15,7 @@ pub enum AddressObjectProp { AddressData(String), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "AddressObjectPropWrapperName", untagged)] pub enum AddressObjectPropWrapper { AddressObject(AddressObjectProp), diff --git a/crates/carddav/src/address_object/service.rs b/crates/carddav/src/address_object/service.rs index e23725b..1c6efdc 100644 --- a/crates/carddav/src/address_object/service.rs +++ b/crates/carddav/src/address_object/service.rs @@ -98,9 +98,8 @@ where D: Deserializer<'de>, { let name: String = Deserialize::deserialize(deserializer)?; - if let Some(object_id) = name.strip_suffix(".vcf") { - Ok(object_id.to_owned()) - } else { - Err(serde::de::Error::custom("Missing .vcf extension")) - } + name.strip_suffix(".vcf").map_or_else( + || Err(serde::de::Error::custom("Missing .vcf extension")), + |object_id| Ok(object_id.to_owned()), + ) } diff --git a/crates/carddav/src/addressbook/methods/mkcol.rs b/crates/carddav/src/addressbook/methods/mkcol.rs index 6fdc9af..8a64173 100644 --- a/crates/carddav/src/addressbook/methods/mkcol.rs +++ b/crates/carddav/src/addressbook/methods/mkcol.rs @@ -127,6 +127,6 @@ mod tests { } } } - ) + ); } } diff --git a/crates/carddav/src/addressbook/methods/post.rs b/crates/carddav/src/addressbook/methods/post.rs index 7b89a5e..96ef1e3 100644 --- a/crates/carddav/src/addressbook/methods/post.rs +++ b/crates/carddav/src/addressbook/methods/post.rs @@ -49,7 +49,8 @@ pub async fn route_post( push_resource: request .subscription .web_push_subscription - .push_resource.clone(), + .push_resource + .clone(), topic: addressbook_resource.0.push_topic, expiration: expires.naive_local(), public_key: request diff --git a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs index ae41dcb..16e46ce 100644 --- a/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs +++ b/crates/carddav/src/addressbook/methods/report/addressbook_multiget.rs @@ -47,11 +47,9 @@ pub async fn get_objects_addressbook_multiget( } } else { not_found.push(href.to_owned()); - continue; } } else { not_found.push(href.to_owned()); - continue; } } diff --git a/crates/carddav/src/addressbook/methods/report/mod.rs b/crates/carddav/src/addressbook/methods/report/mod.rs index 283f806..feb6aea 100644 --- a/crates/carddav/src/addressbook/methods/report/mod.rs +++ b/crates/carddav/src/addressbook/methods/report/mod.rs @@ -28,8 +28,8 @@ pub(crate) enum ReportRequest { impl ReportRequest { const fn props(&self) -> &PropfindType { match self { - Self::AddressbookMultiget(AddressbookMultigetRequest { prop, .. }) => prop, - Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, + Self::AddressbookMultiget(AddressbookMultigetRequest { prop, .. }) + | Self::SyncCollection(SyncCollectionRequest { prop, .. }) => prop, } } } @@ -101,7 +101,7 @@ mod tests { assert_eq!( report_request, ReportRequest::SyncCollection(SyncCollectionRequest { - sync_token: "".to_owned(), + sync_token: String::new(), sync_level: SyncLevel::One, prop: rustical_dav::xml::PropfindType::Prop(PropElement( vec![AddressObjectPropWrapperName::AddressObject( @@ -111,7 +111,7 @@ mod tests { )), limit: None }) - ) + ); } #[test] @@ -142,6 +142,6 @@ mod tests { "/carddav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned() ] }) - ) + ); } } diff --git a/crates/carddav/src/addressbook/prop.rs b/crates/carddav/src/addressbook/prop.rs index def843f..48165a2 100644 --- a/crates/carddav/src/addressbook/prop.rs +++ b/crates/carddav/src/addressbook/prop.rs @@ -6,7 +6,7 @@ use rustical_dav_push::DavPushExtensionProp; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use strum_macros::VariantArray; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "AddressbookPropName")] pub enum AddressbookProp { // CardDAV (RFC 6352) @@ -20,7 +20,7 @@ pub enum AddressbookProp { MaxResourceSize(i64), } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "AddressbookPropWrapperName", untagged)] pub enum AddressbookPropWrapper { Addressbook(AddressbookProp), diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index d62904b..fcaea04 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -59,7 +59,7 @@ impl Resource for AddressbookResource { AddressbookPropWrapperName::Addressbook(prop) => { AddressbookPropWrapper::Addressbook(match prop { AddressbookPropName::MaxResourceSize => { - AddressbookProp::MaxResourceSize(10000000) + AddressbookProp::MaxResourceSize(10_000_000) } AddressbookPropName::SupportedReportSet => { AddressbookProp::SupportedReportSet(SupportedReportSet::all()) @@ -92,9 +92,11 @@ impl Resource for AddressbookResource { self.0.description = description; Ok(()) } - AddressbookProp::MaxResourceSize(_) => Err(rustical_dav::Error::PropReadOnly), - AddressbookProp::SupportedReportSet(_) => Err(rustical_dav::Error::PropReadOnly), - AddressbookProp::SupportedAddressData(_) => Err(rustical_dav::Error::PropReadOnly), + AddressbookProp::MaxResourceSize(_) + | AddressbookProp::SupportedReportSet(_) + | AddressbookProp::SupportedAddressData(_) => { + Err(rustical_dav::Error::PropReadOnly) + } }, AddressbookPropWrapper::SyncToken(prop) => SyncTokenExtension::set_prop(self, prop), AddressbookPropWrapper::DavPush(prop) => DavPushExtension::set_prop(self, prop), @@ -112,9 +114,11 @@ impl Resource for AddressbookResource { self.0.description = None; Ok(()) } - AddressbookPropName::MaxResourceSize => Err(rustical_dav::Error::PropReadOnly), - AddressbookPropName::SupportedReportSet => Err(rustical_dav::Error::PropReadOnly), - AddressbookPropName::SupportedAddressData => Err(rustical_dav::Error::PropReadOnly), + AddressbookPropName::MaxResourceSize + | AddressbookPropName::SupportedReportSet + | AddressbookPropName::SupportedAddressData => { + Err(rustical_dav::Error::PropReadOnly) + } }, AddressbookPropWrapperName::SyncToken(prop) => { SyncTokenExtension::remove_prop(self, prop) diff --git a/crates/carddav/src/error.rs b/crates/carddav/src/error.rs index a79df8f..fff3ffc 100644 --- a/crates/carddav/src/error.rs +++ b/crates/carddav/src/error.rs @@ -30,7 +30,8 @@ pub enum Error { } impl Error { - #[must_use] pub const fn status_code(&self) -> StatusCode { + #[must_use] + pub const fn status_code(&self) -> StatusCode { match self { Self::StoreError(err) => match err { rustical_store::Error::NotFound => StatusCode::NOT_FOUND, @@ -38,11 +39,10 @@ impl Error { rustical_store::Error::ReadOnly => StatusCode::FORBIDDEN, _ => StatusCode::INTERNAL_SERVER_ERROR, }, - Self::ChronoParseError(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::DavError(err) => err.status_code(), Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::XmlDecodeError(_) => StatusCode::BAD_REQUEST, - Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, + Self::ChronoParseError(_) | Self::NotImplemented => StatusCode::INTERNAL_SERVER_ERROR, Self::NotFound => StatusCode::NOT_FOUND, Self::IcalError(err) => err.status_code(), } diff --git a/crates/carddav/src/lib.rs b/crates/carddav/src/lib.rs index f9638c2..9c013be 100644 --- a/crates/carddav/src/lib.rs +++ b/crates/carddav/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] use axum::response::Redirect; use axum::routing::any; use axum::{Extension, Router}; @@ -37,20 +38,15 @@ pub fn carddav_router, subscription_store: Arc, ) -> Router { - let principal_service = PrincipalResourceService::new( - store, - auth_provider.clone(), - subscription_store, - ); + let principal_service = + PrincipalResourceService::new(store, auth_provider.clone(), subscription_store); Router::new() .nest( prefix, - RootResourceService::<_, Principal, CardDavPrincipalUri>::new( - principal_service, - ) - .axum_router() - .layer(AuthenticationLayer::new(auth_provider)) - .layer(Extension(CardDavPrincipalUri(prefix))), + RootResourceService::<_, Principal, CardDavPrincipalUri>::new(principal_service) + .axum_router() + .layer(AuthenticationLayer::new(auth_provider)) + .layer(Extension(CardDavPrincipalUri(prefix))), ) .route( "/.well-known/carddav", diff --git a/crates/carddav/src/principal/prop.rs b/crates/carddav/src/principal/prop.rs index 2689589..2d56992 100644 --- a/crates/carddav/src/principal/prop.rs +++ b/crates/carddav/src/principal/prop.rs @@ -30,7 +30,7 @@ pub enum PrincipalProp { #[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone)] pub struct AddressbookHomeSet(#[xml(ty = "untagged", flatten)] pub Vec); -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, EnumVariants, PropName)] #[xml(unit_variants_ident = "PrincipalPropWrapperName", untagged)] pub enum PrincipalPropWrapper { Principal(PrincipalProp), diff --git a/crates/dav/src/error.rs b/crates/dav/src/error.rs index ab614cd..1d0e386 100644 --- a/crates/dav/src/error.rs +++ b/crates/dav/src/error.rs @@ -35,9 +35,9 @@ pub enum Error { } impl Error { - #[must_use] pub const fn status_code(&self) -> StatusCode { + #[must_use] + pub const fn status_code(&self) -> StatusCode { match self { - Self::InternalError => StatusCode::INTERNAL_SERVER_ERROR, Self::NotFound => StatusCode::NOT_FOUND, Self::BadRequest(_) => StatusCode::BAD_REQUEST, Self::Unauthorized => StatusCode::UNAUTHORIZED, @@ -52,7 +52,7 @@ impl Error { }, Self::PropReadOnly => StatusCode::CONFLICT, Self::PreconditionFailed => StatusCode::PRECONDITION_FAILED, - Self::IOError(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::InternalError | Self::IOError(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::Forbidden => StatusCode::FORBIDDEN, } } diff --git a/crates/dav/src/extensions/common.rs b/crates/dav/src/extensions/common.rs index b9ad129..0592252 100644 --- a/crates/dav/src/extensions/common.rs +++ b/crates/dav/src/extensions/common.rs @@ -6,7 +6,7 @@ use crate::{ }; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, PropName, EnumVariants)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)] #[xml(unit_variants_ident = "CommonPropertiesPropName")] pub enum CommonPropertiesProp { // WebDAV (RFC 2518) @@ -39,9 +39,9 @@ pub trait CommonPropertiesExtension: Resource { CommonPropertiesPropName::Resourcetype => { CommonPropertiesProp::Resourcetype(self.get_resourcetype()) } - CommonPropertiesPropName::Displayname => { - CommonPropertiesProp::Displayname(self.get_displayname().map(std::string::ToString::to_string)) - } + CommonPropertiesPropName::Displayname => CommonPropertiesProp::Displayname( + self.get_displayname().map(std::string::ToString::to_string), + ), CommonPropertiesPropName::CurrentUserPrincipal => { CommonPropertiesProp::CurrentUserPrincipal( principal_uri.principal_uri(principal.get_id()).into(), diff --git a/crates/dav/src/header/depth.rs b/crates/dav/src/header/depth.rs index 70baa92..21ee497 100644 --- a/crates/dav/src/header/depth.rs +++ b/crates/dav/src/header/depth.rs @@ -85,10 +85,11 @@ impl FromRequestParts for Depth { parts: &mut axum::http::request::Parts, _state: &S, ) -> Result { - if let Some(depth_header) = parts.headers.get("Depth") { - depth_header.as_bytes().try_into() - } else { - Ok(Self::Zero) - } + parts + .headers + .get("Depth") + .map_or(Ok(Self::Zero), |depth_header| { + depth_header.as_bytes().try_into() + }) } } diff --git a/crates/dav/src/header/overwrite.rs b/crates/dav/src/header/overwrite.rs index 3cd646e..1238c1c 100644 --- a/crates/dav/src/header/overwrite.rs +++ b/crates/dav/src/header/overwrite.rs @@ -30,11 +30,10 @@ impl FromRequestParts for Overwrite { parts: &mut axum::http::request::Parts, _state: &S, ) -> Result { - if let Some(overwrite_header) = parts.headers.get("Overwrite") { - overwrite_header.as_bytes().try_into() - } else { - Ok(Self::default()) - } + parts.headers.get("Overwrite").map_or_else( + || Ok(Self::default()), + |overwrite_header| overwrite_header.as_bytes().try_into(), + ) } } @@ -60,7 +59,7 @@ mod tests { #[tokio::test] async fn test_overwrite_default() { let request = Request::put("asd").body(()).unwrap(); - let (mut parts, _) = request.into_parts(); + let (mut parts, ()) = request.into_parts(); let overwrite = Overwrite::from_request_parts(&mut parts, &()) .await .unwrap(); diff --git a/crates/dav/src/lib.rs b/crates/dav/src/lib.rs index 3d2c179..3d0fe97 100644 --- a/crates/dav/src/lib.rs +++ b/crates/dav/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc)] pub mod error; pub mod extensions; pub mod header; diff --git a/crates/dav/src/privileges.rs b/crates/dav/src/privileges.rs index bc7ebb2..aff7bdf 100644 --- a/crates/dav/src/privileges.rs +++ b/crates/dav/src/privileges.rs @@ -47,7 +47,8 @@ pub struct UserPrivilegeSet { } impl UserPrivilegeSet { - #[must_use] pub fn has(&self, privilege: &UserPrivilege) -> bool { + #[must_use] + pub fn has(&self, privilege: &UserPrivilege) -> bool { if (privilege == &UserPrivilege::WriteProperties || privilege == &UserPrivilege::WriteContent) && self.privileges.contains(&UserPrivilege::Write) @@ -57,13 +58,15 @@ impl UserPrivilegeSet { self.privileges.contains(privilege) || self.privileges.contains(&UserPrivilege::All) } - #[must_use] pub fn all() -> Self { + #[must_use] + pub fn all() -> Self { Self { privileges: HashSet::from([UserPrivilege::All]), } } - #[must_use] pub fn owner_only(is_owner: bool) -> Self { + #[must_use] + pub fn owner_only(is_owner: bool) -> Self { if is_owner { Self::all() } else { @@ -71,7 +74,8 @@ impl UserPrivilegeSet { } } - #[must_use] pub fn owner_read(is_owner: bool) -> Self { + #[must_use] + pub fn owner_read(is_owner: bool) -> Self { if is_owner { Self::read_only() } else { @@ -79,7 +83,8 @@ impl UserPrivilegeSet { } } - #[must_use] pub fn owner_write_properties(is_owner: bool) -> Self { + #[must_use] + pub fn owner_write_properties(is_owner: bool) -> Self { // Content is read-only but we can write properties if is_owner { Self::write_properties() @@ -88,7 +93,8 @@ impl UserPrivilegeSet { } } - #[must_use] pub fn read_only() -> Self { + #[must_use] + pub fn read_only() -> Self { Self { privileges: HashSet::from([ UserPrivilege::Read, @@ -98,7 +104,8 @@ impl UserPrivilegeSet { } } - #[must_use] pub fn write_properties() -> Self { + #[must_use] + pub fn write_properties() -> Self { Self { privileges: HashSet::from([ UserPrivilege::Read, diff --git a/crates/dav/src/resource/axum_methods.rs b/crates/dav/src/resource/axum_methods.rs index 98b6fed..6c6a6a1 100644 --- a/crates/dav/src/resource/axum_methods.rs +++ b/crates/dav/src/resource/axum_methods.rs @@ -9,42 +9,50 @@ pub type MethodFunction = pub trait AxumMethods: Sized + Send + Sync + 'static { #[inline] - #[must_use] fn report() -> Option> { + #[must_use] + fn report() -> Option> { None } #[inline] - #[must_use] fn get() -> Option> { + #[must_use] + fn get() -> Option> { None } #[inline] - #[must_use] fn post() -> Option> { + #[must_use] + fn post() -> Option> { None } #[inline] - #[must_use] fn mkcol() -> Option> { + #[must_use] + fn mkcol() -> Option> { None } #[inline] - #[must_use] fn mkcalendar() -> Option> { + #[must_use] + fn mkcalendar() -> Option> { None } #[inline] - #[must_use] fn put() -> Option> { + #[must_use] + fn put() -> Option> { None } #[inline] - #[must_use] fn import() -> Option> { + #[must_use] + fn import() -> Option> { None } #[inline] - #[must_use] fn allow_header() -> Allow { + #[must_use] + fn allow_header() -> Allow { let mut allow = vec![ Method::from_str("PROPFIND").unwrap(), Method::from_str("PROPPATCH").unwrap(), diff --git a/crates/dav/src/resource/mod.rs b/crates/dav/src/resource/mod.rs index 9717ce1..5d4f7ed 100644 --- a/crates/dav/src/resource/mod.rs +++ b/crates/dav/src/resource/mod.rs @@ -42,7 +42,8 @@ pub trait Resource: Clone + Send + 'static { fn get_resourcetype(&self) -> Resourcetype; - #[must_use] fn list_props() -> Vec<(Option>, &'static str)> { + #[must_use] + fn list_props() -> Vec<(Option>, &'static str)> { Self::Prop::variant_names() } @@ -75,27 +76,27 @@ pub trait Resource: Clone + Send + 'static { } fn satisfies_if_match(&self, if_match: &IfMatch) -> bool { - if let Some(etag) = self.get_etag() { - if let Ok(etag) = ETag::from_str(&etag) { - if_match.precondition_passes(&etag) - } else { - if_match.is_any() - } - } else { - if_match.is_any() - } + self.get_etag().map_or_else( + || if_match.is_any(), + |etag| { + ETag::from_str(&etag).map_or_else( + |_| if_match.is_any(), + |etag| if_match.precondition_passes(&etag), + ) + }, + ) } fn satisfies_if_none_match(&self, if_none_match: &IfNoneMatch) -> bool { - if let Some(etag) = self.get_etag() { - if let Ok(etag) = ETag::from_str(&etag) { - if_none_match.precondition_passes(&etag) - } else { - if_none_match != &IfNoneMatch::any() - } - } else { - if_none_match != &IfNoneMatch::any() - } + self.get_etag().map_or_else( + || if_none_match != &IfNoneMatch::any(), + |etag| { + ETag::from_str(&etag).map_or_else( + |_| if_none_match != &IfNoneMatch::any(), + |etag| if_none_match.precondition_passes(&etag), + ) + }, + ) } fn get_user_privileges( diff --git a/crates/dav/src/resource/resource_service.rs b/crates/dav/src/resource/resource_service.rs index 837ad46..49d3365 100644 --- a/crates/dav/src/resource/resource_service.rs +++ b/crates/dav/src/resource/resource_service.rs @@ -76,10 +76,7 @@ pub trait ResourceService: Clone + Sized + Send + Sync + AxumMethods + 'static { Err(crate::Error::Forbidden.into()) } - fn axum_service(self) -> AxumService - where - Self: AxumMethods, - { + fn axum_service(self) -> AxumService { AxumService::new(self) } diff --git a/crates/dav/src/xml/href.rs b/crates/dav/src/xml/href.rs index 8faba2c..80b7a46 100644 --- a/crates/dav/src/xml/href.rs +++ b/crates/dav/src/xml/href.rs @@ -8,7 +8,8 @@ pub struct HrefElement { } impl HrefElement { - #[must_use] pub const fn new(href: String) -> Self { + #[must_use] + pub const fn new(href: String) -> Self { Self { href } } } diff --git a/crates/dav/src/xml/multistatus.rs b/crates/dav/src/xml/multistatus.rs index 689a105..0df60bb 100644 --- a/crates/dav/src/xml/multistatus.rs +++ b/crates/dav/src/xml/multistatus.rs @@ -19,6 +19,7 @@ pub struct PropstatElement { pub status: StatusCode, } +#[allow(clippy::trivially_copy_pass_by_ref)] fn xml_serialize_status( status: &StatusCode, ns: Option, @@ -56,6 +57,7 @@ pub struct ResponseElement { pub propstat: Vec>, } +#[allow(clippy::trivially_copy_pass_by_ref, clippy::ref_option)] fn xml_serialize_optional_status( val: &Option, ns: Option, diff --git a/crates/dav/src/xml/propfind.rs b/crates/dav/src/xml/propfind.rs index 7e85ed7..2fb51e8 100644 --- a/crates/dav/src/xml/propfind.rs +++ b/crates/dav/src/xml/propfind.rs @@ -6,7 +6,7 @@ use rustical_xml::XmlDeserialize; use rustical_xml::XmlError; use rustical_xml::XmlRootTag; -#[derive(Debug, Clone, XmlDeserialize, XmlRootTag, PartialEq)] +#[derive(Debug, Clone, XmlDeserialize, XmlRootTag, PartialEq, Eq)] #[xml(root = "propfind", ns = "crate::namespace::NS_DAV")] pub struct PropfindElement { #[xml(ty = "untagged")] diff --git a/crates/dav/src/xml/report_set.rs b/crates/dav/src/xml/report_set.rs index e5c5323..5640157 100644 --- a/crates/dav/src/xml/report_set.rs +++ b/crates/dav/src/xml/report_set.rs @@ -10,7 +10,8 @@ pub struct SupportedReportSet { } impl SupportedReportSet { - #[must_use] pub fn new(methods: Vec) -> Self { + #[must_use] + pub fn new(methods: Vec) -> Self { Self { supported_report: methods .into_iter() diff --git a/crates/dav/src/xml/resourcetype.rs b/crates/dav/src/xml/resourcetype.rs index 0a00bde..bc28e4e 100644 --- a/crates/dav/src/xml/resourcetype.rs +++ b/crates/dav/src/xml/resourcetype.rs @@ -40,6 +40,6 @@ mod tests { "# - ) + ); } } diff --git a/crates/dav/src/xml/sync_collection.rs b/crates/dav/src/xml/sync_collection.rs index 30fa10b..3ea7db9 100644 --- a/crates/dav/src/xml/sync_collection.rs +++ b/crates/dav/src/xml/sync_collection.rs @@ -56,7 +56,7 @@ impl From for u64 { #[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct NresultsElement(#[xml(ty = "text")] u64); -#[derive(XmlDeserialize, Clone, Debug, PartialEq, XmlRootTag)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq, XmlRootTag)] // // // @@ -106,11 +106,11 @@ mod tests { assert_eq!( request, SyncCollectionRequest { - sync_token: "".to_owned(), + sync_token: String::new(), sync_level: SyncLevel::One, prop: PropfindType::Prop(PropElement(vec![TestPropName::Getetag], vec![])), limit: Some(100.into()) } - ) + ); } } diff --git a/crates/dav/src/xml/tag_list.rs b/crates/dav/src/xml/tag_list.rs index 41779e3..0b23dac 100644 --- a/crates/dav/src/xml/tag_list.rs +++ b/crates/dav/src/xml/tag_list.rs @@ -17,15 +17,13 @@ impl XmlSerialize for TagList { namespaces: &HashMap, writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { - let prefix = ns - .and_then(|ns| namespaces.get(&ns)) - .map(|prefix| { - if prefix.is_empty() { - String::new() - } else { - format!("{prefix}:") - } - }); + let prefix = ns.and_then(|ns| namespaces.get(&ns)).map(|prefix| { + if prefix.is_empty() { + String::new() + } else { + format!("{prefix}:") + } + }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); diff --git a/crates/dav_push/src/extension.rs b/crates/dav_push/src/extension.rs index 266675e..781b05e 100644 --- a/crates/dav_push/src/extension.rs +++ b/crates/dav_push/src/extension.rs @@ -2,7 +2,7 @@ use crate::{ContentUpdate, PropertyUpdate, SupportedTriggers, Transports, Trigge use rustical_dav::header::Depth; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, PropName, EnumVariants)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Eq, Clone, PropName, EnumVariants)] #[xml(unit_variants_ident = "DavPushExtensionPropName")] pub enum DavPushExtensionProp { // WebDav Push @@ -32,7 +32,7 @@ pub trait DavPushExtension { ) -> Result { Ok(match &prop { DavPushExtensionPropName::Transports => { - DavPushExtensionProp::Transports(Default::default()) + DavPushExtensionProp::Transports(Transports::default()) } DavPushExtensionPropName::Topic => DavPushExtensionProp::Topic(self.get_topic()), DavPushExtensionPropName::SupportedTriggers => { diff --git a/crates/dav_push/src/lib.rs b/crates/dav_push/src/lib.rs index 431061e..068dd9f 100644 --- a/crates/dav_push/src/lib.rs +++ b/crates/dav_push/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc)] mod extension; mod prop; pub mod register; @@ -69,6 +70,7 @@ impl DavPushController { } } + #[allow(clippy::cognitive_complexity)] async fn send_message(&self, message: CollectionOperation) { let subscriptions = match self.sub_store.get_subscriptions(&message.topic).await { Ok(subs) => subs, diff --git a/crates/dav_push/src/prop.rs b/crates/dav_push/src/prop.rs index 01237a1..fd681a0 100644 --- a/crates/dav_push/src/prop.rs +++ b/crates/dav_push/src/prop.rs @@ -7,7 +7,7 @@ pub enum Transport { WebPush, } -#[derive(Debug, Clone, XmlSerialize, PartialEq)] +#[derive(Debug, Clone, XmlSerialize, PartialEq, Eq)] pub struct Transports { #[xml(flatten, ty = "untagged")] #[xml(ns = "crate::namespace::NS_DAVPUSH")] @@ -22,10 +22,10 @@ impl Default for Transports { } } -#[derive(XmlSerialize, XmlDeserialize, PartialEq, Clone)] +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Clone)] pub struct SupportedTriggers(#[xml(flatten, ty = "untagged")] pub Vec); -#[derive(XmlSerialize, XmlDeserialize, PartialEq, Debug, Clone)] +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Eq, Debug, Clone)] pub enum Trigger { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] ContentUpdate(ContentUpdate), diff --git a/crates/dav_push/src/register.rs b/crates/dav_push/src/register.rs index d721050..6cae633 100644 --- a/crates/dav_push/src/register.rs +++ b/crates/dav_push/src/register.rs @@ -1,7 +1,7 @@ use crate::Trigger; use rustical_xml::{XmlDeserialize, XmlRootTag, XmlSerialize}; -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] #[xml(ns = "crate::namespace::NS_DAVPUSH")] pub struct WebPushSubscription { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] @@ -23,16 +23,16 @@ pub struct SubscriptionPublicKey { pub key: String, } -#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, Clone, Debug, PartialEq, Eq)] pub struct SubscriptionElement { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] pub web_push_subscription: WebPushSubscription, } -#[derive(XmlDeserialize, XmlSerialize, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, XmlSerialize, Clone, Debug, PartialEq, Eq)] pub struct TriggerElement(#[xml(ty = "untagged", flatten)] Vec); -#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)] +#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq, Eq)] #[xml(root = "push-register")] #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] pub struct PushRegister { @@ -100,6 +100,6 @@ mod tests { Trigger::PropertyUpdate(PropertyUpdate(Depth::Zero)), ])) } - ) + ); } } diff --git a/crates/frontend/src/assets.rs b/crates/frontend/src/assets.rs index bb65521..b5d9bc5 100644 --- a/crates/frontend/src/assets.rs +++ b/crates/frontend/src/assets.rs @@ -8,7 +8,7 @@ use futures_core::future::BoxFuture; use headers::{ContentType, ETag, HeaderMapExt}; use http::{Method, StatusCode}; use rust_embed::RustEmbed; -use std::{convert::Infallible, marker::PhantomData, str::FromStr}; +use std::{borrow::Cow, convert::Infallible, marker::PhantomData, str::FromStr}; use tower::Service; #[derive(Clone, RustEmbed, Default)] @@ -16,6 +16,7 @@ use tower::Service; #[allow(dead_code)] // Since this is not used with the frontend-dev feature pub struct Assets; +#[allow(dead_code)] #[derive(Clone, Default)] pub struct EmbedService where @@ -41,6 +42,7 @@ where } #[inline] + #[allow(clippy::similar_names)] fn call(&mut self, mut req: Request) -> Self::Future { Box::pin(async move { if req.method() != Method::GET && req.method() != Method::HEAD { @@ -60,7 +62,7 @@ where let mime = mime_guess::from_path(path).first_or_octet_stream(); let body = if req.method() == Method::HEAD { - Default::default() + Cow::default() } else { data }; diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index 0aee30b..91bebd2 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -48,7 +48,7 @@ pub fn frontend_router Router { let user_router = Router::new() .route("/", get(route_get_home)) - .route("/{user}", get(route_user_named::)) + .route("/{user}", get(route_user_named::)) // App token management .route("/{user}/app_token", post(route_post_app_token::)) .route( diff --git a/crates/frontend/src/nextcloud_login/routes.rs b/crates/frontend/src/nextcloud_login/routes.rs index ce25b5e..773d328 100644 --- a/crates/frontend/src/nextcloud_login/routes.rs +++ b/crates/frontend/src/nextcloud_login/routes.rs @@ -27,20 +27,22 @@ pub async fn post_nextcloud_login( let token = uuid::Uuid::new_v4().to_string(); let app_name = user_agent.to_string(); - let mut flows = state.flows.write().await; - // Flows must not last longer than 10 minutes - // We also enforce that condition here to prevent a memory leak where unpolled flows would - // never be cleaned up - flows.retain(|_, flow| Utc::now() - flow.created_at < Duration::minutes(10)); - flows.insert( - flow_id.clone(), - NextcloudFlow { - app_name: app_name.clone(), - created_at: Utc::now(), - token: token.clone(), - response: None, - }, - ); + { + let mut flows = state.flows.write().await; + // Flows must not last longer than 10 minutes + // We also enforce that condition here to prevent a memory leak where unpolled flows would + // never be cleaned up + flows.retain(|_, flow| Utc::now() - flow.created_at < Duration::minutes(10)); + flows.insert( + flow_id.clone(), + NextcloudFlow { + app_name: app_name.clone(), + created_at: Utc::now(), + token: token.clone(), + response: None, + }, + ); + } Json(NextcloudLoginResponse { login: format!("https://{host}/index.php/login/v2/flow/{flow_id}"), poll: NextcloudLoginPoll { @@ -56,6 +58,7 @@ pub struct NextcloudPollForm { token: String, } +#[allow(clippy::significant_drop_tightening)] pub async fn post_nextcloud_poll( Extension(state): Extension>, Path(flow_id): Path, diff --git a/crates/frontend/src/oidc_user_store.rs b/crates/frontend/src/oidc_user_store.rs index e40c7d8..8399733 100644 --- a/crates/frontend/src/oidc_user_store.rs +++ b/crates/frontend/src/oidc_user_store.rs @@ -1,8 +1,7 @@ -use std::sync::Arc; - use async_trait::async_trait; use rustical_oidc::UserStore; -use rustical_store::auth::{AuthenticationProvider, Principal}; +use rustical_store::auth::{AuthenticationProvider, Principal, PrincipalType}; +use std::sync::Arc; pub struct OidcUserStore(pub Arc); @@ -26,7 +25,7 @@ impl UserStore for OidcUserStore { Principal { id: id.to_owned(), displayname: None, - principal_type: Default::default(), + principal_type: PrincipalType::default(), password: None, memberships: vec![], }, diff --git a/crates/frontend/src/routes/addressbook.rs b/crates/frontend/src/routes/addressbook.rs index 4652896..66e80d0 100644 --- a/crates/frontend/src/routes/addressbook.rs +++ b/crates/frontend/src/routes/addressbook.rs @@ -42,8 +42,8 @@ pub async fn route_addressbook_restore( return Ok(StatusCode::UNAUTHORIZED.into_response()); } store.restore_addressbook(&owner, &addressbook_id).await?; - Ok(match referer { - Some(referer) => Redirect::to(&referer.to_string()).into_response(), - None => (StatusCode::CREATED, "Restored").into_response(), - }) + Ok(referer.map_or_else( + || (StatusCode::CREATED, "Restored").into_response(), + |referer| Redirect::to(&referer.to_string()).into_response(), + )) } diff --git a/crates/frontend/src/routes/calendar.rs b/crates/frontend/src/routes/calendar.rs index 617dcb1..37c5428 100644 --- a/crates/frontend/src/routes/calendar.rs +++ b/crates/frontend/src/routes/calendar.rs @@ -42,8 +42,8 @@ pub async fn route_calendar_restore( return Ok(StatusCode::UNAUTHORIZED.into_response()); } store.restore_calendar(&owner, &cal_id).await?; - Ok(match referer { - Some(referer) => Redirect::to(&referer.to_string()).into_response(), - None => (StatusCode::CREATED, "Restored").into_response(), - }) + Ok(referer.map_or_else( + || (StatusCode::CREATED, "Restored").into_response(), + |referer| Redirect::to(&referer.to_string()).into_response(), + )) } diff --git a/crates/frontend/src/routes/user.rs b/crates/frontend/src/routes/user.rs index c2bc7cb..237b824 100644 --- a/crates/frontend/src/routes/user.rs +++ b/crates/frontend/src/routes/user.rs @@ -10,10 +10,7 @@ use axum::{ use axum_extra::{TypedHeader, extract::Host}; use headers::UserAgent; use http::StatusCode; -use rustical_store::{ - AddressbookStore, CalendarStore, - auth::{AppToken, AuthenticationProvider, Principal}, -}; +use rustical_store::auth::{AppToken, AuthenticationProvider, Principal}; use crate::pages::user::{Section, UserPage}; @@ -32,14 +29,8 @@ pub struct ProfileSection { pub davx5_hostname: Option, } -pub async fn route_user_named< - CS: CalendarStore, - AS: AddressbookStore, - AP: AuthenticationProvider, ->( +pub async fn route_user_named( Path(user_id): Path, - Extension(cal_store): Extension>, - Extension(addr_store): Extension>, Extension(auth_provider): Extension>, TypedHeader(user_agent): TypedHeader, Host(host): Host, @@ -49,26 +40,6 @@ pub async fn route_user_named< return StatusCode::UNAUTHORIZED.into_response(); } - let mut calendars = vec![]; - for group in user.memberships() { - calendars.extend(cal_store.get_calendars(group).await.unwrap()); - } - - let mut deleted_calendars = vec![]; - for group in user.memberships() { - deleted_calendars.extend(cal_store.get_deleted_calendars(group).await.unwrap()); - } - - let mut addressbooks = vec![]; - for group in user.memberships() { - addressbooks.extend(addr_store.get_addressbooks(group).await.unwrap()); - } - - let mut deleted_addressbooks = vec![]; - for group in user.memberships() { - deleted_addressbooks.extend(addr_store.get_deleted_addressbooks(group).await.unwrap()); - } - let is_apple = user_agent.as_str().contains("Apple") || user_agent.as_str().contains("Mac OS"); let davx5_hostname = user_agent.as_str().contains("Android").then_some(host); diff --git a/crates/ical/Cargo.toml b/crates/ical/Cargo.toml index c51d9ab..a02cb26 100644 --- a/crates/ical/Cargo.toml +++ b/crates/ical/Cargo.toml @@ -15,7 +15,6 @@ thiserror.workspace = true derive_more.workspace = true rustical_xml.workspace = true ical.workspace = true -lazy_static.workspace = true regex.workspace = true rrule.workspace = true serde.workspace = true diff --git a/crates/ical/src/address_object.rs b/crates/ical/src/address_object.rs index 5726036..40f5082 100644 --- a/crates/ical/src/address_object.rs +++ b/crates/ical/src/address_object.rs @@ -22,7 +22,7 @@ impl TryFrom for AddressObject { fn try_from(vcard: VcardContact) -> Result { let uid = vcard .get_uid() - .ok_or(Error::InvalidData("missing UID".to_owned()))? + .ok_or_else(|| Error::InvalidData("missing UID".to_owned()))? .to_owned(); let vcf = vcard.generate(); Ok(Self { @@ -45,32 +45,38 @@ impl AddressObject { Ok(Self { id, vcf, vcard }) } - #[must_use] pub fn get_id(&self) -> &str { + #[must_use] + pub fn get_id(&self) -> &str { &self.id } - #[must_use] pub fn get_etag(&self) -> String { + #[must_use] + pub fn get_etag(&self) -> String { let mut hasher = Sha256::new(); hasher.update(self.get_id()); hasher.update(self.get_vcf()); format!("\"{:x}\"", hasher.finalize()) } - #[must_use] pub fn get_vcf(&self) -> &str { + #[must_use] + pub fn get_vcf(&self) -> &str { &self.vcf } - #[must_use] pub fn get_anniversary(&self) -> Option<(CalDateTime, bool)> { + #[must_use] + pub fn get_anniversary(&self) -> Option<(CalDateTime, bool)> { let prop = self.vcard.get_property("ANNIVERSARY")?.value.as_deref()?; CalDateTime::parse_vcard(prop).ok() } - #[must_use] pub fn get_birthday(&self) -> Option<(CalDateTime, bool)> { + #[must_use] + pub fn get_birthday(&self) -> Option<(CalDateTime, bool)> { let prop = self.vcard.get_property("BDAY")?.value.as_deref()?; CalDateTime::parse_vcard(prop).ok() } - #[must_use] pub fn get_full_name(&self) -> Option<&str> { + #[must_use] + pub fn get_full_name(&self) -> Option<&str> { let prop = self.vcard.get_property("FN")?; prop.value.as_deref() } @@ -78,9 +84,7 @@ impl AddressObject { pub fn get_anniversary_object(&self) -> Result, Error> { Ok( if let Some((anniversary, contains_year)) = self.get_anniversary() { - let fullname = if let Some(name) = self.get_full_name() { - name - } else { + let Some(fullname) = self.get_full_name() else { return Ok(None); }; let anniversary = anniversary.date(); @@ -122,9 +126,7 @@ END:VCALENDAR", pub fn get_birthday_object(&self) -> Result, Error> { Ok( if let Some((birthday, contains_year)) = self.get_birthday() { - let fullname = if let Some(name) = self.get_full_name() { - name - } else { + let Some(fullname) = self.get_full_name() else { return Ok(None); }; let birthday = birthday.date(); diff --git a/crates/ical/src/error.rs b/crates/ical/src/error.rs index 5805901..52ff7e7 100644 --- a/crates/ical/src/error.rs +++ b/crates/ical/src/error.rs @@ -24,10 +24,12 @@ pub enum Error { } impl Error { - #[must_use] pub const fn status_code(&self) -> StatusCode { + #[must_use] + pub const fn status_code(&self) -> StatusCode { match self { - Self::InvalidData(_) => StatusCode::BAD_REQUEST, - Self::MissingCalendar | Self::MissingContact => StatusCode::BAD_REQUEST, + Self::InvalidData(_) | Self::MissingCalendar | Self::MissingContact => { + StatusCode::BAD_REQUEST + } _ => StatusCode::INTERNAL_SERVER_ERROR, } } diff --git a/crates/ical/src/icalendar/event.rs b/crates/ical/src/icalendar/event.rs index 25ad480..4ed18cb 100644 --- a/crates/ical/src/icalendar/event.rs +++ b/crates/ical/src/icalendar/event.rs @@ -15,7 +15,8 @@ pub struct EventObject { } impl EventObject { - #[must_use] pub fn get_uid(&self) -> &str { + #[must_use] + pub fn get_uid(&self) -> &str { self.event.get_uid() } @@ -70,9 +71,9 @@ impl EventObject { for prop in &self.event.properties { rrule_set = match prop.name.as_str() { "RRULE" => { - let rrule = RRule::from_str(prop.value.as_ref().ok_or(Error::RRuleError( - rrule::ParseError::MissingDateGenerationRules.into(), - ))?)? + let rrule = RRule::from_str(prop.value.as_ref().ok_or_else(|| { + Error::RRuleError(rrule::ParseError::MissingDateGenerationRules.into()) + })?)? .validate(dtstart) .unwrap(); rrule_set.rrule(rrule) @@ -120,8 +121,8 @@ impl EventObject { date.format() }; - for _override in overrides { - if let Some(override_id) = &_override + for ev_override in overrides { + if let Some(override_id) = &ev_override .event .get_recurrence_id() .as_ref() @@ -131,7 +132,7 @@ impl EventObject { { // We have an override for this occurence // - events.push(_override.event.clone()); + events.push(ev_override.event.clone()); continue 'recurrence; } } @@ -185,7 +186,7 @@ mod tests { use crate::CalendarObject; use ical::generator::Emitter; - const ICS: &str = r#"BEGIN:VCALENDAR + const ICS: &str = r"BEGIN:VCALENDAR CALSCALE:GREGORIAN VERSION:2.0 BEGIN:VTIMEZONE @@ -203,7 +204,7 @@ SUMMARY:weekly stuff TRANSP:OPAQUE RRULE:FREQ=WEEKLY;COUNT=4;INTERVAL=2;BYDAY=TU,TH,SU END:VEVENT -END:VCALENDAR"#; +END:VCALENDAR"; const EXPANDED: [&str; 4] = [ "BEGIN:VEVENT\r @@ -251,13 +252,7 @@ END:VEVENT\r\n", #[test] fn test_expand_recurrence() { let event = CalendarObject::from_ics(ICS.to_string()).unwrap(); - let (event, overrides) = if let crate::CalendarObjectComponent::Event( - main_event, - overrides, - ) = event.get_data() - { - (main_event, overrides) - } else { + let crate::CalendarObjectComponent::Event(event, overrides) = event.get_data() else { panic!() }; diff --git a/crates/ical/src/icalendar/object.rs b/crates/ical/src/icalendar/object.rs index 9dbe7c5..c02b52f 100644 --- a/crates/ical/src/icalendar/object.rs +++ b/crates/ical/src/icalendar/object.rs @@ -26,7 +26,8 @@ pub enum CalendarObjectType { } impl CalendarObjectType { - #[must_use] pub const fn as_str(&self) -> &'static str { + #[must_use] + pub const fn as_str(&self) -> &'static str { match self { Self::Event => "VEVENT", Self::Todo => "VTODO", @@ -208,15 +209,18 @@ impl CalendarObject { }) } - #[must_use] pub const fn get_vtimezones(&self) -> &HashMap { + #[must_use] + pub const fn get_vtimezones(&self) -> &HashMap { &self.vtimezones } - #[must_use] pub const fn get_data(&self) -> &CalendarObjectComponent { + #[must_use] + pub const fn get_data(&self) -> &CalendarObjectComponent { &self.data } - #[must_use] pub fn get_id(&self) -> &str { + #[must_use] + pub fn get_id(&self) -> &str { match &self.data { // We've made sure before that the first component exists and all components share the // same UID @@ -226,22 +230,26 @@ impl CalendarObject { } } - #[must_use] pub fn get_etag(&self) -> String { + #[must_use] + pub fn get_etag(&self) -> String { let mut hasher = Sha256::new(); hasher.update(self.get_id()); hasher.update(self.get_ics()); format!("\"{:x}\"", hasher.finalize()) } - #[must_use] pub fn get_ics(&self) -> &str { + #[must_use] + pub fn get_ics(&self) -> &str { &self.ics } - #[must_use] pub fn get_component_name(&self) -> &str { + #[must_use] + pub fn get_component_name(&self) -> &str { self.get_object_type().as_str() } - #[must_use] pub fn get_object_type(&self) -> CalendarObjectType { + #[must_use] + pub fn get_object_type(&self) -> CalendarObjectType { (&self.data).into() } @@ -249,7 +257,7 @@ impl CalendarObject { match &self.data { CalendarObjectComponent::Event(main_event, overrides) => Ok(overrides .iter() - .chain([main_event].into_iter()) + .chain(std::iter::once(main_event)) .map(super::event::EventObject::get_dtstart) .collect::, _>>()? .into_iter() @@ -263,7 +271,7 @@ impl CalendarObject { match &self.data { CalendarObjectComponent::Event(main_event, overrides) => Ok(overrides .iter() - .chain([main_event].into_iter()) + .chain(std::iter::once(main_event)) .map(super::event::EventObject::get_last_occurence) .collect::, _>>()? .into_iter() diff --git a/crates/ical/src/lib.rs b/crates/ical/src/lib.rs index a02d1c8..9c00d52 100644 --- a/crates/ical/src/lib.rs +++ b/crates/ical/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] mod timestamp; mod timezone; pub use timestamp::*; diff --git a/crates/ical/src/timestamp.rs b/crates/ical/src/timestamp.rs index 74a9720..f96ad9d 100644 --- a/crates/ical/src/timestamp.rs +++ b/crates/ical/src/timestamp.rs @@ -3,14 +3,11 @@ use chrono::{DateTime, Datelike, Duration, Local, NaiveDate, NaiveDateTime, Naiv use chrono_tz::Tz; use derive_more::derive::Deref; use ical::property::Property; -use lazy_static::lazy_static; use rustical_xml::{ValueDeserialize, ValueSerialize}; -use std::{borrow::Cow, collections::HashMap, ops::Add}; +use std::{borrow::Cow, collections::HashMap, ops::Add, sync::LazyLock}; -lazy_static! { - static ref RE_VCARD_DATE_MM_DD: regex::Regex = - regex::Regex::new(r"^--(?\d{2})(?\d{2})$").unwrap(); -} +static RE_VCARD_DATE_MM_DD: LazyLock = + LazyLock::new(|| regex::Regex::new(r"^--(?\d{2})(?\d{2})$").unwrap()); const LOCAL_DATE_TIME: &str = "%Y%m%dT%H%M%S"; const UTC_DATE_TIME: &str = "%Y%m%dT%H%M%SZ"; @@ -137,9 +134,7 @@ impl CalDateTime { let prop_value = prop .value .as_ref() - .ok_or(CalDateTimeError::InvalidDatetimeFormat( - "empty property".to_owned(), - ))?; + .ok_or_else(|| CalDateTimeError::InvalidDatetimeFormat("empty property".into()))?; let timezone = if let Some(tzid) = prop.get_param("TZID") { if let Some(timezone) = timezones.get(tzid) { @@ -158,7 +153,8 @@ impl CalDateTime { Self::parse(prop_value, timezone) } - #[must_use] pub fn format(&self) -> String { + #[must_use] + pub fn format(&self) -> String { match self { Self::DateTime(datetime) => match datetime.timezone() { ICalTimezone::Olson(chrono_tz::UTC) => datetime.format(UTC_DATE_TIME).to_string(), @@ -168,25 +164,29 @@ impl CalDateTime { } } - #[must_use] pub fn format_date(&self) -> String { + #[must_use] + pub fn format_date(&self) -> String { match self { Self::DateTime(datetime) => datetime.format(LOCAL_DATE).to_string(), Self::Date(date, _) => date.format(LOCAL_DATE).to_string(), } } - #[must_use] pub fn date(&self) -> NaiveDate { + #[must_use] + pub fn date(&self) -> NaiveDate { match self { Self::DateTime(datetime) => datetime.date_naive(), Self::Date(date, _) => date.to_owned(), } } - #[must_use] pub const fn is_date(&self) -> bool { + #[must_use] + pub const fn is_date(&self) -> bool { matches!(&self, Self::Date(_, _)) } - #[must_use] pub fn as_datetime(&self) -> Cow<'_, DateTime> { + #[must_use] + pub fn as_datetime(&self) -> Cow<'_, DateTime> { match self { Self::DateTime(datetime) => Cow::Borrowed(datetime), Self::Date(date, tz) => Cow::Owned( @@ -219,8 +219,7 @@ impl CalDateTime { if let Ok(datetime) = NaiveDateTime::parse_from_str(value, UTC_DATE_TIME) { return Ok(datetime.and_utc().into()); } - let timezone = timezone - .map_or(ICalTimezone::Local, ICalTimezone::Olson); + let timezone = timezone.map_or(ICalTimezone::Local, ICalTimezone::Olson); if let Ok(date) = NaiveDate::parse_from_str(value, LOCAL_DATE) { return Ok(Self::Date(date, timezone)); } @@ -251,7 +250,7 @@ impl CalDateTime { return Ok(( Self::Date( NaiveDate::from_ymd_opt(year, month, day) - .ok_or(CalDateTimeError::ParseError(value.to_string()))?, + .ok_or_else(|| CalDateTimeError::ParseError(value.to_string()))?, ICalTimezone::Local, ), false, @@ -260,11 +259,13 @@ impl CalDateTime { Err(CalDateTimeError::InvalidDatetimeFormat(value.to_string())) } - #[must_use] pub fn utc(&self) -> DateTime { + #[must_use] + pub fn utc(&self) -> DateTime { self.as_datetime().to_utc() } - #[must_use] pub fn timezone(&self) -> ICalTimezone { + #[must_use] + pub fn timezone(&self) -> ICalTimezone { match &self { Self::DateTime(datetime) => datetime.timezone(), Self::Date(_, tz) => tz.to_owned(), @@ -349,9 +350,7 @@ impl Datelike for CalDateTime { fn with_month0(&self, month0: u32) -> Option { match &self { Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_month0(month0)?)), - Self::Date(date, tz) => { - Some(Self::Date(date.with_month0(month0)?, tz.to_owned())) - } + Self::Date(date, tz) => Some(Self::Date(date.with_month0(month0)?, tz.to_owned())), } } fn with_day(&self, day: u32) -> Option { @@ -368,22 +367,14 @@ impl Datelike for CalDateTime { } fn with_ordinal(&self, ordinal: u32) -> Option { match &self { - Self::DateTime(datetime) => { - Some(Self::DateTime(datetime.with_ordinal(ordinal)?)) - } - Self::Date(date, tz) => { - Some(Self::Date(date.with_ordinal(ordinal)?, tz.to_owned())) - } + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_ordinal(ordinal)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_ordinal(ordinal)?, tz.to_owned())), } } fn with_ordinal0(&self, ordinal0: u32) -> Option { match &self { - Self::DateTime(datetime) => { - Some(Self::DateTime(datetime.with_ordinal0(ordinal0)?)) - } - Self::Date(date, tz) => { - Some(Self::Date(date.with_ordinal0(ordinal0)?, tz.to_owned())) - } + Self::DateTime(datetime) => Some(Self::DateTime(datetime.with_ordinal0(ordinal0)?)), + Self::Date(date, tz) => Some(Self::Date(date.with_ordinal0(ordinal0)?, tz.to_owned())), } } } diff --git a/crates/oidc/src/lib.rs b/crates/oidc/src/lib.rs index eb63b0c..5e74250 100644 --- a/crates/oidc/src/lib.rs +++ b/crates/oidc/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] use axum::{ Extension, Form, extract::Query, diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 20049b3..98823af 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -15,7 +15,6 @@ sha2 = { workspace = true } ical = { workspace = true } chrono = { workspace = true } regex = { workspace = true } -lazy_static = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } chrono-tz = { workspace = true } diff --git a/crates/store/src/addressbook.rs b/crates/store/src/addressbook.rs index 120781c..05016b8 100644 --- a/crates/store/src/addressbook.rs +++ b/crates/store/src/addressbook.rs @@ -14,7 +14,8 @@ pub struct Addressbook { } impl Addressbook { - #[must_use] pub fn format_synctoken(&self) -> String { + #[must_use] + pub fn format_synctoken(&self) -> String { format_synctoken(self.synctoken) } } diff --git a/crates/store/src/auth/middleware.rs b/crates/store/src/auth/middleware.rs index f8a75b7..5c94ff8 100644 --- a/crates/store/src/auth/middleware.rs +++ b/crates/store/src/auth/middleware.rs @@ -53,9 +53,9 @@ impl Clone for AuthenticationMiddleware Service for AuthenticationMiddleware +impl Service for AuthenticationMiddleware where - S: Service + Send + 'static, + S: Service + Send + Clone + 'static, S::Future: Send + 'static, { type Response = S::Response; diff --git a/crates/store/src/auth/principal.rs b/crates/store/src/auth/principal.rs index 4ca71f7..6d69224 100644 --- a/crates/store/src/auth/principal.rs +++ b/crates/store/src/auth/principal.rs @@ -35,7 +35,8 @@ impl Principal { /// Returns true if the user is either /// - the principal itself /// - has full access to the prinicpal (is member) - #[must_use] pub fn is_principal(&self, principal: &str) -> bool { + #[must_use] + pub fn is_principal(&self, principal: &str) -> bool { if self.id == principal { return true; } diff --git a/crates/store/src/auth/principal_type.rs b/crates/store/src/auth/principal_type.rs index 69a5ca3..c9102fb 100644 --- a/crates/store/src/auth/principal_type.rs +++ b/crates/store/src/auth/principal_type.rs @@ -36,7 +36,8 @@ impl TryFrom<&str> for PrincipalType { } impl PrincipalType { - #[must_use] pub const fn as_str(&self) -> &'static str { + #[must_use] + pub const fn as_str(&self) -> &'static str { match self { Self::Individual => "INDIVIDUAL", Self::Group => "GROUP", diff --git a/crates/store/src/calendar.rs b/crates/store/src/calendar.rs index a8a7567..31e6a1c 100644 --- a/crates/store/src/calendar.rs +++ b/crates/store/src/calendar.rs @@ -32,17 +32,20 @@ pub struct Calendar { } impl Calendar { - #[must_use] pub fn format_synctoken(&self) -> String { + #[must_use] + pub fn format_synctoken(&self) -> String { format_synctoken(self.synctoken) } - #[must_use] pub fn get_timezone(&self) -> Option { + #[must_use] + pub fn get_timezone(&self) -> Option { self.timezone_id .as_ref() .and_then(|tzid| chrono_tz::Tz::from_str(tzid).ok()) } - #[must_use] pub fn get_vtimezone(&self) -> Option<&'static str> { + #[must_use] + pub fn get_vtimezone(&self) -> Option<&'static str> { self.timezone_id .as_ref() .and_then(|tzid| vtimezones_rs::VTIMEZONES.get(tzid).copied()) diff --git a/crates/store/src/combined_calendar_store.rs b/crates/store/src/combined_calendar_store.rs index 2a7110c..d90130a 100644 --- a/crates/store/src/combined_calendar_store.rs +++ b/crates/store/src/combined_calendar_store.rs @@ -20,6 +20,7 @@ impl CombinedCalendarStore { } } + #[must_use] pub fn with_store(mut self, store: Arc) -> Self { let store: Arc = store; self.stores.insert(CS::PREFIX, store); @@ -30,8 +31,7 @@ impl CombinedCalendarStore { self.stores .iter() .find(|&(prefix, _store)| id.starts_with(prefix)) - .map(|(_prefix, store)| store.clone()) - .unwrap_or(self.default.clone()) + .map_or_else(|| self.default.clone(), |(_prefix, store)| store.clone()) } } diff --git a/crates/store/src/error.rs b/crates/store/src/error.rs index 5739b1d..649105c 100644 --- a/crates/store/src/error.rs +++ b/crates/store/src/error.rs @@ -30,7 +30,8 @@ pub enum Error { } impl Error { - #[must_use] pub const fn status_code(&self) -> StatusCode { + #[must_use] + pub const fn status_code(&self) -> StatusCode { match self { Self::NotFound => StatusCode::NOT_FOUND, Self::AlreadyExists => StatusCode::CONFLICT, diff --git a/crates/store/src/synctoken.rs b/crates/store/src/synctoken.rs index b7dbcf9..e21aac2 100644 --- a/crates/store/src/synctoken.rs +++ b/crates/store/src/synctoken.rs @@ -1,10 +1,12 @@ const SYNC_NAMESPACE: &str = "github.com/lennart-k/rustical/ns/"; -#[must_use] pub fn format_synctoken(synctoken: i64) -> String { +#[must_use] +pub fn format_synctoken(synctoken: i64) -> String { format!("{SYNC_NAMESPACE}{synctoken}") } -#[must_use] pub fn parse_synctoken(synctoken: &str) -> Option { +#[must_use] +pub fn parse_synctoken(synctoken: &str) -> Option { if !synctoken.starts_with(SYNC_NAMESPACE) { return None; } diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index b6897a2..1e79857 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -141,10 +141,12 @@ impl SqliteAddressbookStore { if use_trashbin { sqlx::query!( r#"UPDATE addressbooks SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, - principal, addressbook_id + principal, + addressbook_id ) .execute(executor) - .await.map_err(crate::Error::from)?; + .await + .map_err(crate::Error::from)?; } else { sqlx::query!( r#"DELETE FROM addressbooks WHERE (principal, id) = (?, ?)"#, @@ -203,9 +205,7 @@ impl SqliteAddressbookStore { let mut objects = vec![]; let mut deleted_objects = vec![]; - let new_synctoken = changes - .last() - .map_or(0, |&Row { synctoken, .. }| synctoken); + let new_synctoken = changes.last().map_or(0, |&Row { synctoken, .. }| synctoken); for Row { object_id, .. } in changes { match Self::_get_object(&mut *conn, principal, addressbook_id, &object_id, false).await diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 7e0d12b..054ae2e 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -213,21 +213,25 @@ impl SqliteCalendarStore { id: &str, use_trashbin: bool, ) -> Result<(), Error> { - if use_trashbin { sqlx::query!( - r#"UPDATE calendars SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, - principal, - id - ) - .execute(executor) - .await - .map_err(crate::Error::from)? } else { sqlx::query!( - r#"DELETE FROM calendars WHERE (principal, id) = (?, ?)"#, - principal, - id - ) - .execute(executor) - .await - .map_err(crate::Error::from)? }; + if use_trashbin { + sqlx::query!( + r#"UPDATE calendars SET deleted_at = datetime() WHERE (principal, id) = (?, ?)"#, + principal, + id + ) + .execute(executor) + .await + .map_err(crate::Error::from)? + } else { + sqlx::query!( + r#"DELETE FROM calendars WHERE (principal, id) = (?, ?)"#, + principal, + id + ) + .execute(executor) + .await + .map_err(crate::Error::from)? + }; Ok(()) } @@ -476,9 +480,7 @@ impl SqliteCalendarStore { let mut objects = vec![]; let mut deleted_objects = vec![]; - let new_synctoken = changes - .last() - .map_or(0, |&Row { synctoken, .. }| synctoken); + let new_synctoken = changes.last().map_or(0, |&Row { synctoken, .. }| synctoken); for Row { object_id, .. } in changes { match Self::_get_object(&mut *conn, principal, cal_id, &object_id, false).await { diff --git a/crates/store_sqlite/src/lib.rs b/crates/store_sqlite/src/lib.rs index fe94488..52353d7 100644 --- a/crates/store_sqlite/src/lib.rs +++ b/crates/store_sqlite/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc)] pub use error::Error; use serde::Serialize; use sqlx::{Pool, Sqlite, SqlitePool, sqlite::SqliteConnectOptions}; @@ -26,7 +27,8 @@ pub struct SqliteStore { } impl SqliteStore { - #[must_use] pub const fn new(db: SqlitePool) -> Self { + #[must_use] + pub const fn new(db: SqlitePool) -> Self { Self { db } } } diff --git a/crates/store_sqlite/src/principal_store.rs b/crates/store_sqlite/src/principal_store.rs index f774fe4..bdcbac7 100644 --- a/crates/store_sqlite/src/principal_store.rs +++ b/crates/store_sqlite/src/principal_store.rs @@ -195,9 +195,8 @@ impl AuthenticationProvider for SqlitePrincipalStore { Some(user) => user, None => return Ok(None), }; - let password = match &user.password { - Some(password) => password, - None => return Ok(None), + let Some(password) = &user.password else { + return Ok(None); }; if password_auth::verify_password(password_input, password.as_ref()).is_ok() { diff --git a/crates/xml/src/de.rs b/crates/xml/src/de.rs index 25c12a8..4ae00e9 100644 --- a/crates/xml/src/de.rs +++ b/crates/xml/src/de.rs @@ -18,10 +18,7 @@ pub trait XmlDocument: XmlDeserialize { fn parse(reader: quick_xml::NsReader) -> Result; #[inline] - fn parse_reader(input: R) -> Result - where - Self: XmlDeserialize, - { + fn parse_reader(input: R) -> Result { let mut reader = quick_xml::NsReader::from_reader(input); reader.config_mut().trim_text(true); Self::parse(reader) @@ -43,8 +40,7 @@ impl XmlDocument for T { let event = reader.read_event_into(&mut buf)?; let empty = matches!(event, Event::Empty(_)); match event { - Event::Decl(_) => { /* ignore this */ } - Event::Comment(_) => { /* ignore this */ } + Event::Decl(_) | Event::Comment(_) => { /* ignore this */ } Event::Start(start) | Event::Empty(start) => { let (ns, name) = reader.resolve_element(start.name()); let matches = match (Self::root_ns(), &ns, name) { diff --git a/crates/xml/src/lib.rs b/crates/xml/src/lib.rs index 271efc8..1968d5e 100644 --- a/crates/xml/src/lib.rs +++ b/crates/xml/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::missing_errors_doc)] use quick_xml::name::Namespace; use std::collections::HashMap; use std::hash::Hash; diff --git a/crates/xml/src/namespace.rs b/crates/xml/src/namespace.rs index 40b6a67..749827c 100644 --- a/crates/xml/src/namespace.rs +++ b/crates/xml/src/namespace.rs @@ -28,7 +28,8 @@ impl<'a> From<&'a Namespace<'a>> for NamespaceOwned { } impl NamespaceOwned { - #[must_use] pub fn as_ref(&self) -> Namespace<'_> { + #[must_use] + pub fn as_ref(&self) -> Namespace<'_> { Namespace(&self.0) } } diff --git a/crates/xml/src/se.rs b/crates/xml/src/se.rs index ab13622..8c7a6d2 100644 --- a/crates/xml/src/se.rs +++ b/crates/xml/src/se.rs @@ -26,11 +26,8 @@ impl XmlSerialize for Option { namespaces: &HashMap, writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { - if let Some(some) = self { - some.serialize(ns, tag, namespaces, writer) - } else { - Ok(()) - } + self.as_ref() + .map_or(Ok(()), |some| some.serialize(ns, tag, namespaces, writer)) } fn attributes<'a>(&self) -> Option>> { @@ -64,15 +61,13 @@ impl XmlSerialize for () { namespaces: &HashMap, writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { - let prefix = ns - .and_then(|ns| namespaces.get(&ns)) - .map(|prefix| { - if prefix.is_empty() { - String::new() - } else { - [*prefix, ":"].concat() - } - }); + let prefix = ns.and_then(|ns| namespaces.get(&ns)).map(|prefix| { + if prefix.is_empty() { + String::new() + } else { + [*prefix, ":"].concat() + } + }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); if let Some(tagname) = tagname.as_ref() { diff --git a/crates/xml/src/unparsed.rs b/crates/xml/src/unparsed.rs index 37d0708..1a2cdcd 100644 --- a/crates/xml/src/unparsed.rs +++ b/crates/xml/src/unparsed.rs @@ -9,7 +9,8 @@ use crate::{XmlDeserialize, XmlError}; pub struct Unparsed(BytesStart<'static>); impl Unparsed { - #[must_use] pub fn tag_name(&self) -> String { + #[must_use] + pub fn tag_name(&self) -> String { // TODO: respect namespace? String::from_utf8_lossy(self.0.local_name().as_ref()).to_string() } diff --git a/crates/xml/src/value.rs b/crates/xml/src/value.rs index 23d938d..14f2028 100644 --- a/crates/xml/src/value.rs +++ b/crates/xml/src/value.rs @@ -114,15 +114,13 @@ impl XmlSerialize for T { namespaces: &HashMap, writer: &mut quick_xml::Writer<&mut Vec>, ) -> std::io::Result<()> { - let prefix = ns - .and_then(|ns| namespaces.get(&ns)) - .map(|prefix| { - if prefix.is_empty() { - String::new() - } else { - [*prefix, ":"].concat() - } - }); + let prefix = ns.and_then(|ns| namespaces.get(&ns)).map(|prefix| { + if prefix.is_empty() { + String::new() + } else { + [*prefix, ":"].concat() + } + }); let has_prefix = prefix.is_some(); let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); if let Some(tagname) = tagname.as_ref() { diff --git a/src/app.rs b/src/app.rs index 08e5bfd..ff523fa 100644 --- a/src/app.rs +++ b/src/app.rs @@ -28,7 +28,11 @@ use tower_sessions::{Expiry, MemoryStore, SessionManagerLayer}; use tracing::Span; use tracing::field::display; -#[allow(clippy::too_many_arguments)] +#[allow( + clippy::too_many_arguments, + clippy::too_many_lines, + clippy::cognitive_complexity +)] pub fn make_app( addr_store: Arc, cal_store: Arc, @@ -36,7 +40,7 @@ pub fn make_app( auth_provider: Arc, frontend_config: FrontendConfig, oidc_config: Option, - nextcloud_login_config: NextcloudLoginConfig, + nextcloud_login_config: &NextcloudLoginConfig, dav_push_enabled: bool, session_cookie_samesite_strict: bool, payload_limit_mb: usize, diff --git a/src/main.rs b/src/main.rs index 5459874..52ff9ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,7 @@ async fn main() -> Result<()> { principal_store.clone(), config.frontend.clone(), config.oidc.clone(), - config.nextcloud_login.clone(), + &config.nextcloud_login, config.dav_push.enabled, config.http.session_cookie_samesite_strict, config.http.payload_limit_mb, From 255282893aa25cf7feef680e448158db92b65a1f Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:15:38 +0100 Subject: [PATCH 04/15] update matchit --- Cargo.lock | 667 +++++++++++++++++++++++++---------------------------- Cargo.toml | 4 +- 2 files changed, 315 insertions(+), 356 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46c9a53..b2f3292 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -139,7 +139,7 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -175,7 +175,7 @@ checksum = "34921de3d57974069bad483fdfe0ec65d88c4ff892edd1ab4d8b03be0dda1b9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -255,7 +255,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -310,7 +310,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -345,9 +345,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ "axum-core", "bytes", @@ -359,13 +359,12 @@ dependencies = [ "hyper", "hyper-util", "itoa", - "matchit", + "matchit 0.8.4", "memchr", "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -379,9 +378,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -390,7 +389,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -399,9 +397,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" dependencies = [ "axum", "axum-core", @@ -414,17 +412,17 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "serde", - "tower", + "serde_core", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -432,7 +430,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -470,11 +468,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -516,9 +514,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -534,9 +532,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.38" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ "find-msvc-tools", "shlex", @@ -544,9 +542,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -565,7 +563,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -589,9 +587,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -599,9 +597,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -611,21 +609,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" @@ -750,7 +748,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -774,7 +772,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -785,7 +783,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -801,9 +799,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -826,7 +824,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "unicode-xid", ] @@ -850,7 +848,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -972,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -1051,9 +1049,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flume" @@ -1181,7 +1179,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1221,9 +1219,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -1239,29 +1237,29 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -1304,7 +1302,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.4", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -1408,11 +1406,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1579,7 +1577,7 @@ dependencies = [ "lazy_static", "regex", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -1708,9 +1706,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1724,17 +1722,6 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1753,9 +1740,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -1783,9 +1770,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1811,9 +1798,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libm" @@ -1857,11 +1844,10 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", "serde", ] @@ -1896,16 +1882,22 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "matchit" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea5f97102eb9e54ab99fb70bb175589073f554bdadfb74d9bd656482ea73e2a" + [[package]] name = "matchit-serde" version = "0.1.0" -source = "git+https://github.com/lennart-k/matchit-serde?rev=f0591d13#f0591d139ea1c88fa4ee397f3fcb4225fad4c6dc" +source = "git+https://github.com/lennart-k/matchit-serde?rev=e18e65d7#e18e65d75cb20ab5f6a193c84a87ee2db8e6ae0b" dependencies = [ "derive_more", - "matchit", + "matchit 0.9.0", "percent-encoding", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -1951,22 +1943,22 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2044,9 +2036,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -2059,9 +2051,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openidconnect" @@ -2096,9 +2088,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" dependencies = [ "bitflags", "cfg-if", @@ -2117,23 +2109,23 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" dependencies = [ "cc", "libc", @@ -2152,7 +2144,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -2182,7 +2174,7 @@ dependencies = [ "opentelemetry_sdk", "prost", "reqwest", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic", "tracing", @@ -2219,7 +2211,7 @@ dependencies = [ "opentelemetry", "percent-encoding", "rand 0.9.2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -2265,9 +2257,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2275,15 +2267,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2342,7 +2334,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2415,7 +2407,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2479,7 +2471,7 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2521,14 +2513,14 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit 0.23.7", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -2541,7 +2533,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "version_check", "yansi", ] @@ -2566,7 +2558,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2592,7 +2584,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -2605,7 +2597,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", @@ -2613,7 +2605,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -2635,9 +2627,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -2704,43 +2696,43 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2750,9 +2742,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2761,9 +2753,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "relative-path" @@ -2773,9 +2765,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", @@ -2859,7 +2851,7 @@ dependencies = [ "chrono-tz", "log", "regex", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -2907,7 +2899,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.106", + "syn 2.0.108", "unicode-ident", ] @@ -2919,7 +2911,7 @@ checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" dependencies = [ "quote", "rand 0.8.5", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2934,9 +2926,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +checksum = "fb44e1917075637ee8c7bcb865cf8830e3a92b5b1189e44e3a0ab5a0d5be314b" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -2945,22 +2937,22 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +checksum = "382499b49db77a7c19abd2a574f85ada7e9dbe125d5d1160fa5cad7c4cf71fc9" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.106", + "syn 2.0.108", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.7.2" +version = "8.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +checksum = "21fcbee55c2458836bcdbfffb6ec9ba74bbc23ca7aa6816015a3dd2c4d8fc185" dependencies = [ "sha2", "walkdir", @@ -3020,7 +3012,7 @@ dependencies = [ "serde", "sqlx", "tokio", - "toml 0.9.7", + "toml 0.9.8", "tower", "tower-http", "tower-sessions", @@ -3060,7 +3052,7 @@ dependencies = [ "sha2", "strum", "strum_macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tower", "tower-http", @@ -3093,7 +3085,7 @@ dependencies = [ "serde", "strum", "strum_macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tower", "tower-http", @@ -3115,13 +3107,13 @@ dependencies = [ "http", "itertools 0.14.0", "log", - "matchit", + "matchit 0.9.0", "matchit-serde", "quick-xml", "rustical_xml", "serde", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tower", "tracing", @@ -3147,7 +3139,7 @@ dependencies = [ "rustical_store", "rustical_xml", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -3175,7 +3167,7 @@ dependencies = [ "rustical_oidc", "rustical_store", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tower", "tower-http", @@ -3199,7 +3191,7 @@ dependencies = [ "rustical_xml", "serde", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3213,7 +3205,7 @@ dependencies = [ "openidconnect", "reqwest", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tower-sessions", "tracing", ] @@ -3243,7 +3235,7 @@ dependencies = [ "rustical_xml", "serde", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tower", "tower-sessions", @@ -3266,7 +3258,7 @@ dependencies = [ "rustical_store", "serde", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "uuid", @@ -3277,7 +3269,7 @@ name = "rustical_xml" version = "0.9.12" dependencies = [ "quick-xml", - "thiserror 2.0.16", + "thiserror 2.0.17", "xml_derive", ] @@ -3291,14 +3283,14 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" dependencies = [ "once_cell", "ring", @@ -3310,9 +3302,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -3320,9 +3312,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "ring", "rustls-pki-types", @@ -3402,9 +3394,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -3422,22 +3414,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3484,9 +3476,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -3505,19 +3497,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", "schemars 1.0.4", - "serde", - "serde_derive", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -3525,14 +3516,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3614,12 +3605,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3673,7 +3664,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", "memchr", "once_cell", @@ -3682,7 +3673,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -3700,7 +3691,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3723,7 +3714,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.106", + "syn 2.0.108", "tokio", "url", ] @@ -3766,7 +3757,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -3805,7 +3796,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -3831,7 +3822,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", "uuid", @@ -3839,9 +3830,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stringprep" @@ -3875,7 +3866,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3897,9 +3888,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -3923,7 +3914,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -3937,11 +3928,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -3952,18 +3943,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4033,41 +4024,38 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -4111,14 +4099,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde_core", - "serde_spanned 1.0.2", - "toml_datetime 0.7.2", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", "toml_parser", "toml_writer", "winnow", @@ -4135,9 +4123,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] @@ -4148,7 +4136,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -4158,21 +4146,21 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.7.2", + "indexmap 2.12.0", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -4185,9 +4173,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" @@ -4234,7 +4222,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap 2.11.4", + "indexmap 2.12.0", "pin-project-lite", "slab", "sync_wrapper", @@ -4334,7 +4322,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tokio", "tracing", @@ -4372,7 +4360,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4407,7 +4395,7 @@ dependencies = [ "opentelemetry_sdk", "rustversion", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", @@ -4441,9 +4429,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uncased" @@ -4468,9 +4456,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-normalization" @@ -4529,7 +4517,7 @@ version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "rand 0.9.2", "wasm-bindgen", @@ -4595,15 +4583,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -4621,9 +4600,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -4632,25 +4611,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -4661,9 +4626,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4671,31 +4636,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -4713,9 +4678,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] @@ -4736,72 +4701,66 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -4837,16 +4796,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -4882,19 +4841,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -4911,9 +4870,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -4929,9 +4888,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -4947,9 +4906,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -4959,9 +4918,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -4977,9 +4936,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -4995,9 +4954,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -5013,9 +4972,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -5031,9 +4990,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -5065,7 +5024,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5094,7 +5053,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] @@ -5115,7 +5074,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5135,15 +5094,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" @@ -5175,5 +5134,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] diff --git a/Cargo.toml b/Cargo.toml index b0a916c..105bca8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ opentelemetry = [ debug = 0 [workspace.dependencies] -matchit = "0.8" +matchit = "0.9" uuid = { version = "1.11", features = ["v4", "fast-rng"] } async-trait = "0.1" axum = "0.8" @@ -138,7 +138,7 @@ reqwest = { version = "0.12", features = [ ], default-features = false } openidconnect = "4.0" clap = { version = "4.5", features = ["derive", "env"] } -matchit-serde = { git = "https://github.com/lennart-k/matchit-serde", rev = "f0591d13" } +matchit-serde = { git = "https://github.com/lennart-k/matchit-serde", rev = "e18e65d7" } vtimezones-rs = "0.2" ece = { version = "2.3", default-features = false, features = [ "backend-openssl", From 5d142289b3423408ea3ac02c689313ee99f821f6 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:34:20 +0100 Subject: [PATCH 05/15] tokio: Use multi-threaded runtime --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 52ff9ed..ab4ff79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,7 +78,7 @@ async fn get_data_stores( }) } -#[tokio::main] +#[tokio::main(flavor = "multi_thread")] async fn main() -> Result<()> { let args = Args::parse(); From 77d8f5dacc8378835dfb1bc9a058d7518b4de47f Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:12:43 +0100 Subject: [PATCH 06/15] add ping endpoint and healthcheck command --- Dockerfile | 2 ++ src/app.rs | 2 ++ src/commands/health.rs | 25 +++++++++++++++++++++++++ src/commands/mod.rs | 3 ++- src/main.rs | 12 ++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/commands/health.rs diff --git a/Dockerfile b/Dockerfile index ad40229..6afe3aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,3 +47,5 @@ ENV RUSTICAL_DATA_STORE__SQLITE__DB_URL=/var/lib/rustical/db.sqlite3 LABEL org.opencontainers.image.authors="Lennart K github.com/lennart-k" LABEL org.opencontainers.image.licenses="AGPL-3.0-or-later" EXPOSE 4000 + +HEALTHCHECK --interval=30s --timeout=30s --start-period=3s --retries=3 CMD ["/usr/local/bin/rustical", "health"] diff --git a/src/app.rs b/src/app.rs index ff523fa..7634d2c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -50,6 +50,8 @@ pub fn make_app( Arc::new(CombinedCalendarStore::new(cal_store).with_store(birthday_store)); let mut router = Router::new() + // endpoint to be used by healthcheck to see if rustical is online + .route("/ping", axum::routing::get(async || "Pong!")) .merge(caldav_router( "/caldav", auth_provider.clone(), diff --git a/src/commands/health.rs b/src/commands/health.rs new file mode 100644 index 0000000..f5cfe58 --- /dev/null +++ b/src/commands/health.rs @@ -0,0 +1,25 @@ +use crate::config::HttpConfig; +use clap::Parser; +use http::Method; + +#[derive(Parser, Debug)] +pub struct HealthArgs {} + +/// Healthcheck for running rustical instance +/// Currently just pings to see if it's reachable via HTTP +pub async fn cmd_health(http_config: HttpConfig, _health_args: HealthArgs) -> anyhow::Result<()> { + let client = reqwest::ClientBuilder::new().build().unwrap(); + + let endpoint = format!( + "http://{host}:{port}/ping", + host = http_config.host, + port = http_config.port + ) + .parse() + .unwrap(); + let request = reqwest::Request::new(Method::GET, endpoint); + + assert!(client.execute(request).await.unwrap().status().is_success()); + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 7dd5ecd..cd17ea8 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -5,7 +5,8 @@ use crate::config::{ use clap::Parser; use rustical_frontend::FrontendConfig; -mod membership; +pub mod health; +pub mod membership; pub mod principals; #[derive(Debug, Parser)] diff --git a/src/main.rs b/src/main.rs index ab4ff79..b4d88f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery)] +use crate::commands::health::{HealthArgs, cmd_health}; use crate::config::Config; use anyhow::Result; use app::make_app; @@ -45,6 +46,10 @@ struct Args { enum Command { GenConfig(commands::GenConfigArgs), Principals(PrincipalsArgs), + #[command( + about = "Healthcheck for running instance (Used for HEALTHCHECK in Docker container)" + )] + Health(HealthArgs), } async fn get_data_stores( @@ -85,6 +90,13 @@ async fn main() -> Result<()> { match args.command { Some(Command::GenConfig(gen_config_args)) => cmd_gen_config(gen_config_args)?, Some(Command::Principals(principals_args)) => cmd_principals(principals_args).await?, + Some(Command::Health(health_args)) => { + let config: Config = Figment::new() + .merge(Toml::file(&args.config_file)) + .merge(Env::prefixed("RUSTICAL_").split("__")) + .extract()?; + cmd_health(config.http, health_args).await?; + } None => { let config: Config = Figment::new() .merge(Toml::file(&args.config_file)) From 8c2025b6747649381248e045652eb145e78d7a04 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:14:31 +0100 Subject: [PATCH 07/15] version 0.9.13 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2f3292..a3ab65c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2981,7 +2981,7 @@ dependencies = [ [[package]] name = "rustical" -version = "0.9.12" +version = "0.9.13" dependencies = [ "anyhow", "argon2", @@ -3024,7 +3024,7 @@ dependencies = [ [[package]] name = "rustical_caldav" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-std", "async-trait", @@ -3064,7 +3064,7 @@ dependencies = [ [[package]] name = "rustical_carddav" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-trait", "axum", @@ -3096,7 +3096,7 @@ dependencies = [ [[package]] name = "rustical_dav" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-trait", "axum", @@ -3121,7 +3121,7 @@ dependencies = [ [[package]] name = "rustical_dav_push" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-trait", "axum", @@ -3146,7 +3146,7 @@ dependencies = [ [[package]] name = "rustical_frontend" -version = "0.9.12" +version = "0.9.13" dependencies = [ "askama", "askama_web", @@ -3179,7 +3179,7 @@ dependencies = [ [[package]] name = "rustical_ical" -version = "0.9.12" +version = "0.9.13" dependencies = [ "axum", "chrono", @@ -3196,7 +3196,7 @@ dependencies = [ [[package]] name = "rustical_oidc" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-trait", "axum", @@ -3212,7 +3212,7 @@ dependencies = [ [[package]] name = "rustical_store" -version = "0.9.12" +version = "0.9.13" dependencies = [ "anyhow", "async-trait", @@ -3245,7 +3245,7 @@ dependencies = [ [[package]] name = "rustical_store_sqlite" -version = "0.9.12" +version = "0.9.13" dependencies = [ "async-trait", "chrono", @@ -3266,7 +3266,7 @@ dependencies = [ [[package]] name = "rustical_xml" -version = "0.9.12" +version = "0.9.13" dependencies = [ "quick-xml", "thiserror 2.0.17", diff --git a/Cargo.toml b/Cargo.toml index 105bca8..1095286 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["crates/*"] [workspace.package] -version = "0.9.12" +version = "0.9.13" edition = "2024" description = "A CalDAV server" documentation = "https://lennart-k.github.io/rustical/" From f34f56ca8906a6ddd01d355ece27b77a7557717b Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:17:13 +0100 Subject: [PATCH 08/15] update dependencies --- Cargo.lock | 114 +++++++++++++++++++---------------------- Cargo.toml | 2 +- crates/dav/Cargo.toml | 1 - crates/oidc/Cargo.toml | 2 +- 4 files changed, 55 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3ab65c..2667edf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -397,13 +397,14 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +checksum = "460c45604cb25834835e3b4d3468510322852783dac36261d642424d75562ff3" dependencies = [ "axum", "axum-core", "bytes", + "futures-core", "futures-util", "headers", "http", @@ -411,8 +412,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", - "serde_core", "tower-layer", "tower-service", "tracing", @@ -532,9 +531,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -587,9 +586,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -597,9 +596,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -1582,9 +1581,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1595,9 +1594,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1608,11 +1607,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1623,42 +1621,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1838,9 +1832,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -1963,11 +1957,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -2476,9 +2469,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -3312,9 +3305,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -3999,9 +3992,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -4456,24 +4449,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-xid" @@ -5011,9 +5004,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xml_derive" @@ -5035,11 +5028,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5047,9 +5039,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -5106,9 +5098,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -5117,9 +5109,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -5128,9 +5120,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 1095286..091ae30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,7 +121,7 @@ rustical_ical = { path = "./crates/ical/" } chrono-tz = "0.10" chrono-humanize = "0.2" rand = "0.9" -axum-extra = { version = "0.10", features = ["typed-header"] } +axum-extra = { version = "0.12", features = ["typed-header"] } rrule = "0.14" argon2 = "0.5" rpassword = "7.3" diff --git a/crates/dav/Cargo.toml b/crates/dav/Cargo.toml index 5fdd824..1cfbb79 100644 --- a/crates/dav/Cargo.toml +++ b/crates/dav/Cargo.toml @@ -11,7 +11,6 @@ publish = false axum.workspace = true tower.workspace = true axum-extra.workspace = true - rustical_xml.workspace = true async-trait.workspace = true futures-util.workspace = true diff --git a/crates/oidc/Cargo.toml b/crates/oidc/Cargo.toml index b82de92..14ce514 100644 --- a/crates/oidc/Cargo.toml +++ b/crates/oidc/Cargo.toml @@ -14,7 +14,7 @@ reqwest.workspace = true thiserror.workspace = true async-trait.workspace = true axum.workspace = true -tower-sessions = "0.14" +tower-sessions.workspace = true axum-extra.workspace = true headers.workspace = true tracing.workspace = true From 24ab323aa0cfe655389c2b0e54390d90b81f6a2b Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:21:44 +0100 Subject: [PATCH 09/15] clippy appeasement --- crates/dav_push/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/dav_push/src/lib.rs b/crates/dav_push/src/lib.rs index 068dd9f..9b38644 100644 --- a/crates/dav_push/src/lib.rs +++ b/crates/dav_push/src/lib.rs @@ -59,7 +59,7 @@ impl DavPushController { let mut latest_messages = HashMap::new(); for message in messages { 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(); @@ -156,12 +156,13 @@ impl DavPushController { ) -> Result<(), NotifierError> { if subsciption.public_key_type != "p256dh" { return Err(NotifierError::InvalidPublicKeyType( - subsciption.public_key_type.to_string(), + subsciption.public_key_type.clone(), )); } - let endpoint = subsciption.push_resource.parse().map_err(|_| { - NotifierError::InvalidEndpointUrl(subsciption.push_resource.to_string()) - })?; + let endpoint = subsciption + .push_resource + .parse() + .map_err(|_| NotifierError::InvalidEndpointUrl(subsciption.push_resource.clone()))?; let ua_public = base64::engine::general_purpose::URL_SAFE_NO_PAD .decode(&subsciption.public_key) .map_err(|_| NotifierError::InvalidKeyEncoding)?; From f34f7e420e46469c7f63db9279122c280a92cd8f Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:08:36 +0100 Subject: [PATCH 10/15] Dockerfile: Update Rust to 1.91 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6afe3aa..21e7830 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 BUILDPLATFORM From a05baea47213a0d48076e4e935e9007fe07df57d Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:09:42 +0100 Subject: [PATCH 11/15] sqlite_store: Mark write transactions with BEGIN IMMEDIATE Hopefully addresses SQLITE_BUSY error, see #131 --- crates/store_sqlite/src/addressbook_store.rs | 31 ++++++++++++++++---- crates/store_sqlite/src/calendar_store.rs | 31 ++++++++++++++++---- crates/store_sqlite/src/lib.rs | 3 ++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/crates/store_sqlite/src/addressbook_store.rs b/crates/store_sqlite/src/addressbook_store.rs index 1e79857..497bfdb 100644 --- a/crates/store_sqlite/src/addressbook_store.rs +++ b/crates/store_sqlite/src/addressbook_store.rs @@ -1,4 +1,5 @@ use super::ChangeOperation; +use crate::BEGIN_IMMEDIATE; use async_trait::async_trait; use derive_more::derive::Constructor; use rustical_ical::AddressObject; @@ -414,7 +415,11 @@ impl AddressbookStore for SqliteAddressbookStore { addressbook_id: &str, use_trashbin: bool, ) -> 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 = match Self::_get_addressbook(&mut *tx, principal, addressbook_id, use_trashbin).await { @@ -508,7 +513,11 @@ impl AddressbookStore for SqliteAddressbookStore { object: AddressObject, overwrite: bool, ) -> 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(); @@ -554,7 +563,11 @@ impl AddressbookStore for SqliteAddressbookStore { object_id: &str, use_trashbin: bool, ) -> 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?; @@ -589,7 +602,11 @@ impl AddressbookStore for SqliteAddressbookStore { addressbook_id: &str, object_id: &str, ) -> 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?; @@ -624,7 +641,11 @@ impl AddressbookStore for SqliteAddressbookStore { objects: Vec, merge_existing: bool, ) -> 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 = match Self::_get_addressbook(&mut *tx, &addressbook.principal, &addressbook.id, true) diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 054ae2e..1731d1b 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -1,4 +1,5 @@ use super::ChangeOperation; +use crate::BEGIN_IMMEDIATE; use async_trait::async_trait; use chrono::TimeDelta; use derive_more::derive::Constructor; @@ -539,7 +540,11 @@ impl CalendarStore for SqliteCalendarStore { id: &str, use_trashbin: bool, ) -> 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 { Ok(cal) => Some(cal), @@ -573,7 +578,11 @@ impl CalendarStore for SqliteCalendarStore { objects: Vec, merge_existing: bool, ) -> 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 = match Self::_get_calendar(&mut *tx, &calendar.principal, &calendar.id, true).await { @@ -663,7 +672,11 @@ impl CalendarStore for SqliteCalendarStore { object: CalendarObject, overwrite: bool, ) -> 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(); @@ -713,7 +726,11 @@ impl CalendarStore for SqliteCalendarStore { id: &str, use_trashbin: bool, ) -> 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?; @@ -737,7 +754,11 @@ impl CalendarStore for SqliteCalendarStore { cal_id: &str, object_id: &str, ) -> 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?; diff --git a/crates/store_sqlite/src/lib.rs b/crates/store_sqlite/src/lib.rs index 52353d7..fca8f27 100644 --- a/crates/store_sqlite/src/lib.rs +++ b/crates/store_sqlite/src/lib.rs @@ -10,6 +10,9 @@ pub mod error; pub mod principal_store; pub mod subscription_store; +// Begin statement for write transactions +pub const BEGIN_IMMEDIATE: &str = "BEGIN IMMEDIATE"; + #[cfg(any(test, feature = "test"))] pub mod tests; From a53c333f1f5810464a129cf6a5d1d58346a970d5 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:10:06 +0100 Subject: [PATCH 12/15] version 0.9.14 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2667edf..89e48c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2974,7 +2974,7 @@ dependencies = [ [[package]] name = "rustical" -version = "0.9.13" +version = "0.9.14" dependencies = [ "anyhow", "argon2", @@ -3017,7 +3017,7 @@ dependencies = [ [[package]] name = "rustical_caldav" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-std", "async-trait", @@ -3057,7 +3057,7 @@ dependencies = [ [[package]] name = "rustical_carddav" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-trait", "axum", @@ -3089,7 +3089,7 @@ dependencies = [ [[package]] name = "rustical_dav" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-trait", "axum", @@ -3114,7 +3114,7 @@ dependencies = [ [[package]] name = "rustical_dav_push" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-trait", "axum", @@ -3139,7 +3139,7 @@ dependencies = [ [[package]] name = "rustical_frontend" -version = "0.9.13" +version = "0.9.14" dependencies = [ "askama", "askama_web", @@ -3172,7 +3172,7 @@ dependencies = [ [[package]] name = "rustical_ical" -version = "0.9.13" +version = "0.9.14" dependencies = [ "axum", "chrono", @@ -3189,7 +3189,7 @@ dependencies = [ [[package]] name = "rustical_oidc" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-trait", "axum", @@ -3205,7 +3205,7 @@ dependencies = [ [[package]] name = "rustical_store" -version = "0.9.13" +version = "0.9.14" dependencies = [ "anyhow", "async-trait", @@ -3238,7 +3238,7 @@ dependencies = [ [[package]] name = "rustical_store_sqlite" -version = "0.9.13" +version = "0.9.14" dependencies = [ "async-trait", "chrono", @@ -3259,7 +3259,7 @@ dependencies = [ [[package]] name = "rustical_xml" -version = "0.9.13" +version = "0.9.14" dependencies = [ "quick-xml", "thiserror 2.0.17", diff --git a/Cargo.toml b/Cargo.toml index 091ae30..1c17b72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["crates/*"] [workspace.package] -version = "0.9.13" +version = "0.9.14" edition = "2024" description = "A CalDAV server" documentation = "https://lennart-k.github.io/rustical/" From db144ebcae6cb6458384b606f80d5cae4a8da18f Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:23:55 +0100 Subject: [PATCH 13/15] calendarobject: Rename get_id to get_uid --- crates/caldav/src/calendar/methods/report/mod.rs | 2 +- .../caldav/src/calendar/methods/report/sync_collection.rs | 2 +- crates/caldav/src/calendar_object/methods.rs | 4 ++-- crates/caldav/src/calendar_object/resource.rs | 2 +- crates/ical/src/icalendar/object.rs | 4 ++-- crates/store/src/calendar.rs | 3 +-- crates/store_sqlite/src/calendar_store.rs | 8 ++++---- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs index 2703f01..75984e5 100644 --- a/crates/caldav/src/calendar/methods/report/mod.rs +++ b/crates/caldav/src/calendar/methods/report/mod.rs @@ -61,7 +61,7 @@ fn objects_response( ) -> Result, Error> { let mut responses = Vec::new(); for object in objects { - let path = format!("{}/{}.ics", path, object.get_id()); + let path = format!("{}/{}.ics", path, object.get_uid()); responses.push( CalendarObjectResource { object, diff --git a/crates/caldav/src/calendar/methods/report/sync_collection.rs b/crates/caldav/src/calendar/methods/report/sync_collection.rs index 7b70f20..bb11e78 100644 --- a/crates/caldav/src/calendar/methods/report/sync_collection.rs +++ b/crates/caldav/src/calendar/methods/report/sync_collection.rs @@ -33,7 +33,7 @@ pub async fn handle_sync_collection( let mut responses = Vec::new(); for object in new_objects { - let path = format!("{}/{}.ics", path, object.get_id()); + let path = format!("{}/{}.ics", path, object.get_uid()); responses.push( CalendarObjectResource { object, diff --git a/crates/caldav/src/calendar_object/methods.rs b/crates/caldav/src/calendar_object/methods.rs index 510b1ed..177a730 100644 --- a/crates/caldav/src/calendar_object/methods.rs +++ b/crates/caldav/src/calendar_object/methods.rs @@ -82,10 +82,10 @@ pub async fn put_event( debug!("invalid calendar data:\n{body}"); return Err(Error::PreconditionFailed(Precondition::ValidCalendarData)); }; - if object.get_id() != object_id { + if object.get_uid() != object_id { error!( "Calendar object UID and file name not matching: UID={}, filename={}", - object.get_id(), + object.get_uid(), object_id ); return Err(Error::PreconditionFailed(Precondition::MatchingUid)); diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index 15af050..bb54344 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -21,7 +21,7 @@ pub struct CalendarObjectResource { impl ResourceName for CalendarObjectResource { fn get_name(&self) -> String { - format!("{}.ics", self.object.get_id()) + format!("{}.ics", self.object.get_uid()) } } diff --git a/crates/ical/src/icalendar/object.rs b/crates/ical/src/icalendar/object.rs index c02b52f..ce3dbe7 100644 --- a/crates/ical/src/icalendar/object.rs +++ b/crates/ical/src/icalendar/object.rs @@ -220,7 +220,7 @@ impl CalendarObject { } #[must_use] - pub fn get_id(&self) -> &str { + pub fn get_uid(&self) -> &str { match &self.data { // We've made sure before that the first component exists and all components share the // same UID @@ -233,7 +233,7 @@ impl CalendarObject { #[must_use] pub fn get_etag(&self) -> String { let mut hasher = Sha256::new(); - hasher.update(self.get_id()); + hasher.update(self.get_uid()); hasher.update(self.get_ics()); format!("\"{:x}\"", hasher.finalize()) } diff --git a/crates/store/src/calendar.rs b/crates/store/src/calendar.rs index 31e6a1c..da3be24 100644 --- a/crates/store/src/calendar.rs +++ b/crates/store/src/calendar.rs @@ -1,9 +1,8 @@ -use std::str::FromStr; - use crate::synctoken::format_synctoken; use chrono::NaiveDateTime; use rustical_ical::CalendarObjectType; use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct CalendarMetadata { diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index 1731d1b..a24c050 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -24,11 +24,11 @@ impl TryFrom for CalendarObject { fn try_from(value: CalendarObjectRow) -> Result { let object = Self::from_ics(value.ics)?; - if object.get_id() != value.id { + if object.get_uid() != value.id { return Err(rustical_store::Error::IcalError( rustical_ical::Error::InvalidData(format!( "object_id={} and UID={} don't match", - object.get_id(), + object.get_uid(), value.id )), )); @@ -355,7 +355,7 @@ impl SqliteCalendarStore { object: CalendarObject, overwrite: bool, ) -> Result<(), Error> { - let (object_id, ics) = (object.get_id(), object.get_ics()); + let (object_id, ics) = (object.get_uid(), object.get_ics()); let first_occurence = object .get_first_occurence() @@ -678,7 +678,7 @@ impl CalendarStore for SqliteCalendarStore { .await .map_err(crate::Error::from)?; - let object_id = object.get_id().to_owned(); + let object_id = object.get_uid().to_owned(); let calendar = Self::_get_calendar(&mut *tx, &principal, &cal_id, true).await?; if calendar.subscription_url.is_some() { From 76b4194b9498f8f4175e57dd67b833c254219843 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:48:37 +0100 Subject: [PATCH 14/15] lift restriction on object_id and UID having to match addresses #135 --- ...95af5fc963572c90bd10a6616af78757f8c39.json | 32 +++++++++++ ...9311d8cd64108d4f238db4c79e9467a3b6d2e.json | 12 ----- ...0965e45442aca6c5f3b3115738ef508939ed.json} | 12 +++-- ...cc37af3027f6902aa3786365c5ab2fbf06bda.json | 12 ----- ...8f5a96de0fc816ce660c705fb28318be0d42.json} | 12 +++-- ...ba583af5ad84bc1cd8b20cb805e9ce3bad820.json | 12 +++++ ...45e477ef8d29d6186851760757a06dec42339.json | 26 --------- ...50ea739a681ce1f009f05e97f2e101bd7e556.json | 12 +++++ crates/caldav/src/calendar/methods/import.rs | 2 +- .../caldav/src/calendar/methods/report/mod.rs | 2 +- .../methods/report/sync_collection.rs | 2 +- crates/caldav/src/calendar_object/methods.rs | 12 +---- crates/caldav/src/calendar_object/resource.rs | 2 +- crates/caldav/src/error.rs | 2 - crates/ical/src/address_object.rs | 18 ++++--- crates/ical/src/icalendar/event.rs | 2 +- crates/ical/src/icalendar/object.rs | 30 ++++++++--- crates/ical/tests/test_cal_object.rs | 2 +- .../20251101181540_add_calendar_uid.down.sql | 47 ++++++++++++++++ .../20251101181540_add_calendar_uid.up.sql | 53 +++++++++++++++++++ crates/store_sqlite/src/calendar_store.rs | 33 ++++++------ 21 files changed, 234 insertions(+), 103 deletions(-) create mode 100644 .sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json delete mode 100644 .sqlx/query-3e1cca532372e891ab3e604ecb79311d8cd64108d4f238db4c79e9467a3b6d2e.json rename .sqlx/{query-543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d.json => query-505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed.json} (52%) delete mode 100644 .sqlx/query-6327bee90e5df01536a0ddb15adcc37af3027f6902aa3786365c5ab2fbf06bda.json rename .sqlx/{query-54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86.json => query-804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42.json} (53%) create mode 100644 .sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json delete mode 100644 .sqlx/query-c550dbf3d5ce7069f28d767ea9045e477ef8d29d6186851760757a06dec42339.json create mode 100644 .sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json create mode 100644 crates/store_sqlite/migrations/20251101181540_add_calendar_uid.down.sql create mode 100644 crates/store_sqlite/migrations/20251101181540_add_calendar_uid.up.sql diff --git a/.sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json b/.sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json new file mode 100644 index 0000000..f343cd0 --- /dev/null +++ b/.sqlx/query-3a29efff3d3f6e1e05595d1a2d095af5fc963572c90bd10a6616af78757f8c39.json @@ -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" +} diff --git a/.sqlx/query-3e1cca532372e891ab3e604ecb79311d8cd64108d4f238db4c79e9467a3b6d2e.json b/.sqlx/query-3e1cca532372e891ab3e604ecb79311d8cd64108d4f238db4c79e9467a3b6d2e.json deleted file mode 100644 index cd4424e..0000000 --- a/.sqlx/query-3e1cca532372e891ab3e604ecb79311d8cd64108d4f238db4c79e9467a3b6d2e.json +++ /dev/null @@ -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" -} diff --git a/.sqlx/query-543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d.json b/.sqlx/query-505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed.json similarity index 52% rename from .sqlx/query-543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d.json rename to .sqlx/query-505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed.json index 91945b2..73658e2 100644 --- a/.sqlx/query-543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d.json +++ b/.sqlx/query-505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed.json @@ -1,6 +1,6 @@ { "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": { "columns": [ { @@ -9,18 +9,24 @@ "type_info": "Text" }, { - "name": "ics", + "name": "uid", "ordinal": 1, "type_info": "Text" + }, + { + "name": "ics", + "ordinal": 2, + "type_info": "Text" } ], "parameters": { "Right": 4 }, "nullable": [ + false, false, false ] }, - "hash": "543838c030550cb09d1af08adfeade8b7ce3575d92fddbc6e9582d141bc9e49d" + "hash": "505ebe8e64ac709b230dce7150240965e45442aca6c5f3b3115738ef508939ed" } diff --git a/.sqlx/query-6327bee90e5df01536a0ddb15adcc37af3027f6902aa3786365c5ab2fbf06bda.json b/.sqlx/query-6327bee90e5df01536a0ddb15adcc37af3027f6902aa3786365c5ab2fbf06bda.json deleted file mode 100644 index 185ae45..0000000 --- a/.sqlx/query-6327bee90e5df01536a0ddb15adcc37af3027f6902aa3786365c5ab2fbf06bda.json +++ /dev/null @@ -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" -} diff --git a/.sqlx/query-54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86.json b/.sqlx/query-804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42.json similarity index 53% rename from .sqlx/query-54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86.json rename to .sqlx/query-804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42.json index bf83a1f..c67abd7 100644 --- a/.sqlx/query-54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86.json +++ b/.sqlx/query-804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42.json @@ -1,6 +1,6 @@ { "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": { "columns": [ { @@ -9,18 +9,24 @@ "type_info": "Text" }, { - "name": "ics", + "name": "uid", "ordinal": 1, "type_info": "Text" + }, + { + "name": "ics", + "ordinal": 2, + "type_info": "Text" } ], "parameters": { "Right": 2 }, "nullable": [ + false, false, false ] }, - "hash": "54c9c0e36a52e6963f11c6aa27f13aafb4204b8aa34b664fd825bd447db80e86" + "hash": "804ed2a4a7032e9605d1871297498f5a96de0fc816ce660c705fb28318be0d42" } diff --git a/.sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json b/.sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json new file mode 100644 index 0000000..2eee142 --- /dev/null +++ b/.sqlx/query-a68a1b96189b854a7ba2a3cd866ba583af5ad84bc1cd8b20cb805e9ce3bad820.json @@ -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" +} diff --git a/.sqlx/query-c550dbf3d5ce7069f28d767ea9045e477ef8d29d6186851760757a06dec42339.json b/.sqlx/query-c550dbf3d5ce7069f28d767ea9045e477ef8d29d6186851760757a06dec42339.json deleted file mode 100644 index 2c5ddda..0000000 --- a/.sqlx/query-c550dbf3d5ce7069f28d767ea9045e477ef8d29d6186851760757a06dec42339.json +++ /dev/null @@ -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" -} diff --git a/.sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json b/.sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json new file mode 100644 index 0000000..83d624f --- /dev/null +++ b/.sqlx/query-d498a758ed707408b00b7d2675250ea739a681ce1f009f05e97f2e101bd7e556.json @@ -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" +} diff --git a/crates/caldav/src/calendar/methods/import.rs b/crates/caldav/src/calendar/methods/import.rs index 4a82cb2..deb3b05 100644 --- a/crates/caldav/src/calendar/methods/import.rs +++ b/crates/caldav/src/calendar/methods/import.rs @@ -82,7 +82,7 @@ pub async fn route_import( let objects = expanded_cals .into_iter() .map(|cal| cal.generate()) - .map(CalendarObject::from_ics) + .map(|ics| CalendarObject::from_ics(ics, None)) .collect::, _>>()?; let new_cal = Calendar { principal, diff --git a/crates/caldav/src/calendar/methods/report/mod.rs b/crates/caldav/src/calendar/methods/report/mod.rs index 75984e5..2703f01 100644 --- a/crates/caldav/src/calendar/methods/report/mod.rs +++ b/crates/caldav/src/calendar/methods/report/mod.rs @@ -61,7 +61,7 @@ fn objects_response( ) -> Result, Error> { let mut responses = Vec::new(); for object in objects { - let path = format!("{}/{}.ics", path, object.get_uid()); + let path = format!("{}/{}.ics", path, object.get_id()); responses.push( CalendarObjectResource { object, diff --git a/crates/caldav/src/calendar/methods/report/sync_collection.rs b/crates/caldav/src/calendar/methods/report/sync_collection.rs index bb11e78..7b70f20 100644 --- a/crates/caldav/src/calendar/methods/report/sync_collection.rs +++ b/crates/caldav/src/calendar/methods/report/sync_collection.rs @@ -33,7 +33,7 @@ pub async fn handle_sync_collection( let mut responses = Vec::new(); for object in new_objects { - let path = format!("{}/{}.ics", path, object.get_uid()); + let path = format!("{}/{}.ics", path, object.get_id()); responses.push( CalendarObjectResource { object, diff --git a/crates/caldav/src/calendar_object/methods.rs b/crates/caldav/src/calendar_object/methods.rs index 177a730..4e3eb32 100644 --- a/crates/caldav/src/calendar_object/methods.rs +++ b/crates/caldav/src/calendar_object/methods.rs @@ -11,7 +11,7 @@ use rustical_ical::CalendarObject; use rustical_store::CalendarStore; use rustical_store::auth::Principal; use std::str::FromStr; -use tracing::{debug, error, instrument}; +use tracing::{debug, instrument}; #[instrument(skip(cal_store))] pub async fn get_event( @@ -78,18 +78,10 @@ pub async fn put_event( 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}"); return Err(Error::PreconditionFailed(Precondition::ValidCalendarData)); }; - if object.get_uid() != object_id { - error!( - "Calendar object UID and file name not matching: UID={}, filename={}", - object.get_uid(), - object_id - ); - return Err(Error::PreconditionFailed(Precondition::MatchingUid)); - } cal_store .put_object(principal, calendar_id, object, overwrite) .await?; diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index bb54344..15af050 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -21,7 +21,7 @@ pub struct CalendarObjectResource { impl ResourceName for CalendarObjectResource { fn get_name(&self) -> String { - format!("{}.ics", self.object.get_uid()) + format!("{}.ics", self.object.get_id()) } } diff --git a/crates/caldav/src/error.rs b/crates/caldav/src/error.rs index 790646f..833db6c 100644 --- a/crates/caldav/src/error.rs +++ b/crates/caldav/src/error.rs @@ -12,8 +12,6 @@ pub enum Precondition { #[error("valid-calendar-data")] #[xml(ns = "rustical_dav::namespace::NS_CALDAV")] ValidCalendarData, - #[error("matching-uid")] - MatchingUid, } impl IntoResponse for Precondition { diff --git a/crates/ical/src/address_object.rs b/crates/ical/src/address_object.rs index 40f5082..09f73d9 100644 --- a/crates/ical/src/address_object.rs +++ b/crates/ical/src/address_object.rs @@ -97,8 +97,9 @@ impl AddressObject { let uid = format!("{}-anniversary", self.get_id()); let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default(); - Some(CalendarObject::from_ics(format!( - r"BEGIN:VCALENDAR + Some(CalendarObject::from_ics( + format!( + r"BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//github.com/lennart-k/rustical birthday calendar//EN @@ -116,7 +117,9 @@ DESCRIPTION:💍 {fullname}{year_suffix} END:VALARM END:VEVENT END:VCALENDAR", - ))?) + ), + None, + )?) } else { None }, @@ -136,8 +139,9 @@ END:VCALENDAR", let uid = format!("{}-birthday", self.get_id()); let year_suffix = year.map(|year| format!(" ({year})")).unwrap_or_default(); - Some(CalendarObject::from_ics(format!( - r"BEGIN:VCALENDAR + Some(CalendarObject::from_ics( + format!( + r"BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//github.com/lennart-k/rustical birthday calendar//EN @@ -155,7 +159,9 @@ DESCRIPTION:🎂 {fullname}{year_suffix} END:VALARM END:VEVENT END:VCALENDAR", - ))?) + ), + None, + )?) } else { None }, diff --git a/crates/ical/src/icalendar/event.rs b/crates/ical/src/icalendar/event.rs index 4ed18cb..08acfbe 100644 --- a/crates/ical/src/icalendar/event.rs +++ b/crates/ical/src/icalendar/event.rs @@ -251,7 +251,7 @@ END:VEVENT\r\n", #[test] 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 { panic!() }; diff --git a/crates/ical/src/icalendar/object.rs b/crates/ical/src/icalendar/object.rs index ce3dbe7..d31a0a0 100644 --- a/crates/ical/src/icalendar/object.rs +++ b/crates/ical/src/icalendar/object.rs @@ -64,6 +64,19 @@ pub enum CalendarObjectComponent { Journal(IcalJournal, Vec), } +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 { fn from(value: &CalendarObjectComponent) -> Self { match value { @@ -141,12 +154,13 @@ impl CalendarObjectComponent { pub struct CalendarObject { data: CalendarObjectComponent, properties: Vec, + id: String, ics: String, vtimezones: HashMap, } impl CalendarObject { - pub fn from_ics(ics: String) -> Result { + pub fn from_ics(ics: String, id: Option) -> Result { let mut parser = ical::IcalParser::new(BufReader::new(ics.as_bytes())); let cal = parser.next().ok_or(Error::MissingCalendar)??; if parser.next().is_some() { @@ -202,6 +216,7 @@ impl CalendarObject { }; Ok(Self { + id: id.unwrap_or_else(|| data.get_uid().to_owned()), data, properties: cal.properties, ics, @@ -221,13 +236,12 @@ impl CalendarObject { #[must_use] pub fn get_uid(&self) -> &str { - match &self.data { - // 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(), - } + self.data.get_uid() + } + + #[must_use] + pub fn get_id(&self) -> &str { + &self.id } #[must_use] diff --git a/crates/ical/tests/test_cal_object.rs b/crates/ical/tests/test_cal_object.rs index 71db7ab..9fc4ffb 100644 --- a/crates/ical/tests/test_cal_object.rs +++ b/crates/ical/tests/test_cal_object.rs @@ -25,6 +25,6 @@ END:VCALENDAR #[test] 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(); } diff --git a/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.down.sql b/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.down.sql new file mode 100644 index 0000000..ca4e628 --- /dev/null +++ b/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.down.sql @@ -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; diff --git a/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.up.sql b/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.up.sql new file mode 100644 index 0000000..1006424 --- /dev/null +++ b/crates/store_sqlite/migrations/20251101181540_add_calendar_uid.up.sql @@ -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; diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index a24c050..5c47d84 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -17,19 +17,20 @@ use tracing::{error, instrument}; struct CalendarObjectRow { id: String, ics: String, + uid: String, } impl TryFrom for CalendarObject { type Error = rustical_store::Error; fn try_from(value: CalendarObjectRow) -> Result { - let object = Self::from_ics(value.ics)?; - if object.get_uid() != value.id { + let object = Self::from_ics(value.ics, Some(value.id))?; + if object.get_uid() != value.uid { return Err(rustical_store::Error::IcalError( rustical_ical::Error::InvalidData(format!( - "object_id={} and UID={} don't match", - object.get_uid(), - value.id + "uid={} and UID={} don't match", + value.uid, + object.get_uid() )), )); } @@ -281,7 +282,7 @@ impl SqliteCalendarStore { ) -> Result, Error> { sqlx::query_as!( 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, cal_id ) @@ -306,7 +307,7 @@ impl SqliteCalendarStore { sqlx::query_as!( CalendarObjectRow, - r"SELECT id, ics FROM calendarobjects + r"SELECT id, uid, ics FROM calendarobjects WHERE principal = ? AND cal_id = ? AND deleted_at IS NULL AND (last_occurence IS NULL OR ? IS NULL OR last_occurence >= date(?)) AND (first_occurence IS NULL OR ? IS NULL OR first_occurence <= date(?)) @@ -335,7 +336,7 @@ impl SqliteCalendarStore { ) -> Result { sqlx::query_as!( 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, cal_id, object_id, @@ -355,7 +356,7 @@ impl SqliteCalendarStore { object: CalendarObject, overwrite: bool, ) -> Result<(), Error> { - let (object_id, ics) = (object.get_uid(), object.get_ics()); + let (object_id, uid, ics) = (object.get_id(), object.get_uid(), object.get_ics()); let first_occurence = object .get_first_occurence() @@ -374,10 +375,11 @@ impl SqliteCalendarStore { (if overwrite { 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, cal_id, object_id, + uid, ics, first_occurence, last_occurence, @@ -387,10 +389,11 @@ impl SqliteCalendarStore { } else { // If the object already exists a database error is thrown and handled in error.rs 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, cal_id, object_id, + uid, ics, first_occurence, last_occurence, @@ -410,7 +413,7 @@ impl SqliteCalendarStore { executor: E, principal: &str, cal_id: &str, - id: &str, + object_id: &str, use_trashbin: bool, ) -> Result<(), Error> { if use_trashbin { @@ -418,7 +421,7 @@ impl SqliteCalendarStore { "UPDATE calendarobjects SET deleted_at = datetime(), updated_at = datetime() WHERE (principal, cal_id, id) = (?, ?, ?)", principal, cal_id, - id + object_id ) .execute(executor) .await.map_err(crate::Error::from)?; @@ -426,7 +429,7 @@ impl SqliteCalendarStore { sqlx::query!( "DELETE FROM calendarobjects WHERE cal_id = ? AND id = ?", cal_id, - id + object_id ) .execute(executor) .await @@ -678,7 +681,7 @@ impl CalendarStore for SqliteCalendarStore { .await .map_err(crate::Error::from)?; - let object_id = object.get_uid().to_owned(); + let object_id = object.get_id().to_owned(); let calendar = Self::_get_calendar(&mut *tx, &principal, &cal_id, true).await?; if calendar.subscription_url.is_some() { From dabddc628213d6c0e6c54b0b14aebadcee45f807 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 1 Nov 2025 21:49:44 +0100 Subject: [PATCH 15/15] version 0.10.0 --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89e48c2..ba16073 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2974,7 +2974,7 @@ dependencies = [ [[package]] name = "rustical" -version = "0.9.14" +version = "0.10.0" dependencies = [ "anyhow", "argon2", @@ -3017,7 +3017,7 @@ dependencies = [ [[package]] name = "rustical_caldav" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-std", "async-trait", @@ -3057,7 +3057,7 @@ dependencies = [ [[package]] name = "rustical_carddav" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-trait", "axum", @@ -3089,7 +3089,7 @@ dependencies = [ [[package]] name = "rustical_dav" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-trait", "axum", @@ -3114,7 +3114,7 @@ dependencies = [ [[package]] name = "rustical_dav_push" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-trait", "axum", @@ -3139,7 +3139,7 @@ dependencies = [ [[package]] name = "rustical_frontend" -version = "0.9.14" +version = "0.10.0" dependencies = [ "askama", "askama_web", @@ -3172,7 +3172,7 @@ dependencies = [ [[package]] name = "rustical_ical" -version = "0.9.14" +version = "0.10.0" dependencies = [ "axum", "chrono", @@ -3189,7 +3189,7 @@ dependencies = [ [[package]] name = "rustical_oidc" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-trait", "axum", @@ -3205,7 +3205,7 @@ dependencies = [ [[package]] name = "rustical_store" -version = "0.9.14" +version = "0.10.0" dependencies = [ "anyhow", "async-trait", @@ -3238,7 +3238,7 @@ dependencies = [ [[package]] name = "rustical_store_sqlite" -version = "0.9.14" +version = "0.10.0" dependencies = [ "async-trait", "chrono", @@ -3259,7 +3259,7 @@ dependencies = [ [[package]] name = "rustical_xml" -version = "0.9.14" +version = "0.10.0" dependencies = [ "quick-xml", "thiserror 2.0.17", diff --git a/Cargo.toml b/Cargo.toml index 1c17b72..a6c7988 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["crates/*"] [workspace.package] -version = "0.9.14" +version = "0.10.0" edition = "2024" description = "A CalDAV server" documentation = "https://lennart-k.github.io/rustical/"