feat: Add show_deleted to get_calendar

This commit is contained in:
Lennart
2025-06-23 16:35:36 +02:00
parent 8dfb47b28f
commit f9de8a4687
10 changed files with 64 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
{ {
"db_name": "SQLite", "db_name": "SQLite",
"query": "SELECT *\n FROM calendars\n WHERE (principal, id) = (?, ?)", "query": "SELECT *\n FROM calendars\n WHERE (principal, id) = (?, ?)\n AND ((deleted_at IS NULL) OR ?) ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@@ -80,7 +80,7 @@
} }
], ],
"parameters": { "parameters": {
"Right": 2 "Right": 3
}, },
"nullable": [ "nullable": [
false, false,
@@ -100,5 +100,5 @@
false false
] ]
}, },
"hash": "9f930775043a6d4571a8ffd5a981cadf7c51f3f11a189f8461505abec31076e6" "hash": "bb2fa030f2e7c7afdb38c5c54cb31de5293be332d86cf643977d479999542553"
} }

View File

@@ -24,12 +24,16 @@ pub async fn route_get<C: CalendarStore, S: SubscriptionStore>(
return Err(crate::Error::Unauthorized); return Err(crate::Error::Unauthorized);
} }
let calendar = cal_store.get_calendar(&principal, &calendar_id).await?; let calendar = cal_store
.get_calendar(&principal, &calendar_id, true)
.await?;
if !user.is_principal(&calendar.principal) { if !user.is_principal(&calendar.principal) {
return Err(crate::Error::Unauthorized); return Err(crate::Error::Unauthorized);
} }
let calendar = cal_store.get_calendar(&principal, &calendar_id).await?; let calendar = cal_store
.get_calendar(&principal, &calendar_id, true)
.await?;
let mut timezones = HashMap::new(); let mut timezones = HashMap::new();
let objects = cal_store.get_objects(&principal, &calendar_id).await?; let objects = cal_store.get_objects(&principal, &calendar_id).await?;

View File

@@ -25,7 +25,7 @@ pub async fn route_post<C: CalendarStore, S: SubscriptionStore>(
let calendar = resource_service let calendar = resource_service
.cal_store .cal_store
.get_calendar(&principal, &cal_id) .get_calendar(&principal, &cal_id, false)
.await?; .await?;
let calendar_resource = CalendarResource { let calendar_resource = CalendarResource {
cal: calendar, cal: calendar,

View File

@@ -57,7 +57,10 @@ impl<C: CalendarStore, S: SubscriptionStore> ResourceService for CalendarResourc
&self, &self,
(principal, cal_id): &Self::PathComponents, (principal, cal_id): &Self::PathComponents,
) -> Result<Self::Resource, Error> { ) -> Result<Self::Resource, Error> {
let calendar = self.cal_store.get_calendar(principal, cal_id).await?; let calendar = self
.cal_store
.get_calendar(principal, cal_id, false)
.await?;
Ok(CalendarResource { Ok(CalendarResource {
cal: calendar, cal: calendar,
read_only: self.cal_store.is_read_only(cal_id), read_only: self.cal_store.is_read_only(cal_id),

View File

@@ -27,7 +27,9 @@ pub async fn get_event<C: CalendarStore>(
return Err(crate::Error::Unauthorized); return Err(crate::Error::Unauthorized);
} }
let calendar = cal_store.get_calendar(&principal, &calendar_id).await?; let calendar = cal_store
.get_calendar(&principal, &calendar_id, false)
.await?;
if !user.is_principal(&calendar.principal) { if !user.is_principal(&calendar.principal) {
return Err(crate::Error::Unauthorized); return Err(crate::Error::Unauthorized);
} }

View File

@@ -27,7 +27,7 @@ pub async fn route_calendar<C: CalendarStore>(
return Ok(StatusCode::UNAUTHORIZED.into_response()); return Ok(StatusCode::UNAUTHORIZED.into_response());
} }
Ok(CalendarPage { Ok(CalendarPage {
calendar: store.get_calendar(&owner, &cal_id).await?, calendar: store.get_calendar(&owner, &cal_id, true).await?,
} }
.into_response()) .into_response())
} }

View File

@@ -11,7 +11,12 @@ pub struct CalendarQuery {
#[async_trait] #[async_trait]
pub trait CalendarStore: Send + Sync + 'static { pub trait CalendarStore: Send + Sync + 'static {
async fn get_calendar(&self, principal: &str, id: &str) -> Result<Calendar, Error>; async fn get_calendar(
&self,
principal: &str,
id: &str,
show_deleted: bool,
) -> Result<Calendar, Error>;
async fn get_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error>; async fn get_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error>;
async fn get_deleted_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error>; async fn get_deleted_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error>;

View File

@@ -1,8 +1,7 @@
use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use derive_more::Constructor; use derive_more::Constructor;
use rustical_ical::CalendarObject; use rustical_ical::CalendarObject;
use std::sync::Arc;
use crate::{ use crate::{
Calendar, CalendarStore, Error, calendar_store::CalendarQuery, Calendar, CalendarStore, Error, calendar_store::CalendarQuery,
@@ -27,11 +26,20 @@ impl<CS: CalendarStore, BS: CalendarStore> Clone for CombinedCalendarStore<CS, B
#[async_trait] #[async_trait]
impl<CS: CalendarStore, BS: CalendarStore> CalendarStore for CombinedCalendarStore<CS, BS> { impl<CS: CalendarStore, BS: CalendarStore> CalendarStore for CombinedCalendarStore<CS, BS> {
#[inline] #[inline]
async fn get_calendar(&self, principal: &str, id: &str) -> Result<Calendar, Error> { async fn get_calendar(
&self,
principal: &str,
id: &str,
show_deleted: bool,
) -> Result<Calendar, Error> {
if id.starts_with(BIRTHDAYS_PREFIX) { if id.starts_with(BIRTHDAYS_PREFIX) {
self.birthday_store.get_calendar(principal, id).await self.birthday_store
.get_calendar(principal, id, show_deleted)
.await
} else { } else {
self.cal_store.get_calendar(principal, id).await self.cal_store
.get_calendar(principal, id, show_deleted)
.await
} }
} }

View File

@@ -38,11 +38,17 @@ fn birthday_calendar(addressbook: Addressbook) -> Calendar {
/// Objects are all prefixed with BIRTHDAYS_PREFIX /// Objects are all prefixed with BIRTHDAYS_PREFIX
#[async_trait] #[async_trait]
impl<AS: AddressbookStore> CalendarStore for ContactBirthdayStore<AS> { impl<AS: AddressbookStore> CalendarStore for ContactBirthdayStore<AS> {
async fn get_calendar(&self, principal: &str, id: &str) -> Result<Calendar, Error> { async fn get_calendar(
&self,
principal: &str,
id: &str,
show_deleted: bool,
) -> Result<Calendar, Error> {
let id = id.strip_prefix(BIRTHDAYS_PREFIX).ok_or(Error::NotFound)?; let id = id.strip_prefix(BIRTHDAYS_PREFIX).ok_or(Error::NotFound)?;
let addressbook = self.0.get_addressbook(principal, id, false).await?; let addressbook = self.0.get_addressbook(principal, id, show_deleted).await?;
Ok(birthday_calendar(addressbook)) Ok(birthday_calendar(addressbook))
} }
async fn get_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error> { async fn get_calendars(&self, principal: &str) -> Result<Vec<Calendar>, Error> {
let addressbooks = self.0.get_addressbooks(principal).await?; let addressbooks = self.0.get_addressbooks(principal).await?;
Ok(addressbooks.into_iter().map(birthday_calendar).collect()) Ok(addressbooks.into_iter().map(birthday_calendar).collect())

View File

@@ -86,14 +86,17 @@ impl SqliteCalendarStore {
executor: E, executor: E,
principal: &str, principal: &str,
id: &str, id: &str,
show_deleted: bool,
) -> Result<Calendar, Error> { ) -> Result<Calendar, Error> {
let cal = sqlx::query_as!( let cal = sqlx::query_as!(
CalendarRow, CalendarRow,
r#"SELECT * r#"SELECT *
FROM calendars FROM calendars
WHERE (principal, id) = (?, ?)"#, WHERE (principal, id) = (?, ?)
AND ((deleted_at IS NULL) OR ?) "#,
principal, principal,
id id,
show_deleted
) )
.fetch_one(executor) .fetch_one(executor)
.await .await
@@ -470,8 +473,13 @@ impl SqliteCalendarStore {
#[async_trait] #[async_trait]
impl CalendarStore for SqliteCalendarStore { impl CalendarStore for SqliteCalendarStore {
#[instrument] #[instrument]
async fn get_calendar(&self, principal: &str, id: &str) -> Result<Calendar, Error> { async fn get_calendar(
Self::_get_calendar(&self.db, principal, id).await &self,
principal: &str,
id: &str,
show_deleted: bool,
) -> Result<Calendar, Error> {
Self::_get_calendar(&self.db, principal, id, show_deleted).await
} }
#[instrument] #[instrument]
@@ -509,7 +517,7 @@ impl CalendarStore for SqliteCalendarStore {
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut tx = self.db.begin().await.map_err(crate::Error::from)?; let mut tx = self.db.begin().await.map_err(crate::Error::from)?;
let cal = match Self::_get_calendar(&mut *tx, principal, id).await { let cal = match Self::_get_calendar(&mut *tx, principal, id, true).await {
Ok(cal) => Some(cal), Ok(cal) => Some(cal),
Err(Error::NotFound) => None, Err(Error::NotFound) => None,
Err(err) => return Err(err), Err(err) => return Err(err),
@@ -599,7 +607,10 @@ impl CalendarStore for SqliteCalendarStore {
if let Err(err) = self.sender.try_send(CollectionOperation { if let Err(err) = self.sender.try_send(CollectionOperation {
data: CollectionOperationInfo::Content { sync_token }, data: CollectionOperationInfo::Content { sync_token },
topic: self.get_calendar(&principal, &cal_id).await?.push_topic, topic: self
.get_calendar(&principal, &cal_id, true)
.await?
.push_topic,
}) { }) {
error!("Push notification about deleted calendar failed: {err}"); error!("Push notification about deleted calendar failed: {err}");
}; };
@@ -624,7 +635,7 @@ impl CalendarStore for SqliteCalendarStore {
if let Err(err) = self.sender.try_send(CollectionOperation { if let Err(err) = self.sender.try_send(CollectionOperation {
data: CollectionOperationInfo::Content { sync_token }, data: CollectionOperationInfo::Content { sync_token },
topic: self.get_calendar(principal, cal_id).await?.push_topic, topic: self.get_calendar(principal, cal_id, true).await?.push_topic,
}) { }) {
error!("Push notification about deleted calendar failed: {err}"); error!("Push notification about deleted calendar failed: {err}");
}; };
@@ -649,7 +660,7 @@ impl CalendarStore for SqliteCalendarStore {
if let Err(err) = self.sender.try_send(CollectionOperation { if let Err(err) = self.sender.try_send(CollectionOperation {
data: CollectionOperationInfo::Content { sync_token }, data: CollectionOperationInfo::Content { sync_token },
topic: self.get_calendar(principal, cal_id).await?.push_topic, topic: self.get_calendar(principal, cal_id, true).await?.push_topic,
}) { }) {
error!("Push notification about deleted calendar failed: {err}"); error!("Push notification about deleted calendar failed: {err}");
}; };