mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 08:52:16 +00:00
sqlite_store: Refactor notification logic
This commit is contained in:
12
.sqlx/query-583069cbeba5285c63c2b95e989669d3faed66a75fbfc7cd93e5f64b778f45ab.json
generated
Normal file
12
.sqlx/query-583069cbeba5285c63c2b95e989669d3faed66a75fbfc7cd93e5f64b778f45ab.json
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "REPLACE INTO davpush_subscriptions (id, topic, expiration, push_resource, public_key, public_key_type, auth_secret) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 7
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "583069cbeba5285c63c2b95e989669d3faed66a75fbfc7cd93e5f64b778f45ab"
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "INSERT OR REPLACE INTO davpush_subscriptions (id, topic, expiration, push_resource, public_key, public_key_type, auth_secret) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 7
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "6d08d3a014743da9b445ab012437ec11f81fd86d3b02fc1df07a036c6b47ace2"
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ use rustical_store::{
|
|||||||
};
|
};
|
||||||
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};
|
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tracing::{error, instrument, warn};
|
use tracing::{error_span, instrument, warn};
|
||||||
|
|
||||||
pub mod birthday_calendar;
|
pub mod birthday_calendar;
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ impl SqliteAddressbookStore {
|
|||||||
"Commiting orphaned addressbook object ({},{},{}), deleted={}",
|
"Commiting orphaned addressbook object ({},{},{}), deleted={}",
|
||||||
&row.principal, &row.addressbook_id, &row.id, &row.deleted
|
&row.principal, &row.addressbook_id, &row.id, &row.deleted
|
||||||
);
|
);
|
||||||
log_object_operation(
|
Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&row.principal,
|
&row.principal,
|
||||||
&row.addressbook_id,
|
&row.addressbook_id,
|
||||||
@@ -88,6 +88,57 @@ impl SqliteAddressbookStore {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logs an operation to an address object
|
||||||
|
async fn log_object_operation(
|
||||||
|
tx: &mut Transaction<'_, Sqlite>,
|
||||||
|
principal: &str,
|
||||||
|
addressbook_id: &str,
|
||||||
|
object_id: &str,
|
||||||
|
operation: ChangeOperation,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
struct Synctoken {
|
||||||
|
synctoken: i64,
|
||||||
|
}
|
||||||
|
let Synctoken { synctoken } = sqlx::query_as!(
|
||||||
|
Synctoken,
|
||||||
|
r#"
|
||||||
|
UPDATE addressbooks
|
||||||
|
SET synctoken = synctoken + 1
|
||||||
|
WHERE (principal, id) = (?1, ?2)
|
||||||
|
RETURNING synctoken"#,
|
||||||
|
principal,
|
||||||
|
addressbook_id
|
||||||
|
)
|
||||||
|
.fetch_one(&mut **tx)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO addressobjectchangelog (principal, addressbook_id, object_id, "operation", synctoken)
|
||||||
|
VALUES (?1, ?2, ?3, ?4, (
|
||||||
|
SELECT synctoken FROM addressbooks WHERE (principal, id) = (?1, ?2)
|
||||||
|
))"#,
|
||||||
|
principal,
|
||||||
|
addressbook_id,
|
||||||
|
object_id,
|
||||||
|
operation
|
||||||
|
)
|
||||||
|
.execute(&mut **tx)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
Ok(format_synctoken(synctoken))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_push_notification(&self, data: CollectionOperationInfo, topic: String) {
|
||||||
|
if let Err(err) = self.sender.try_send(CollectionOperation { topic, data }) {
|
||||||
|
error_span!(
|
||||||
|
"Error trying to send addressbook update notification:",
|
||||||
|
err = format!("{err:?}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn _get_addressbook<'e, E: Executor<'e, Database = Sqlite>>(
|
async fn _get_addressbook<'e, E: Executor<'e, Database = Sqlite>>(
|
||||||
executor: E,
|
executor: E,
|
||||||
principal: &str,
|
principal: &str,
|
||||||
@@ -496,13 +547,8 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
Self::_delete_addressbook(&mut *tx, principal, addressbook_id, use_trashbin).await?;
|
Self::_delete_addressbook(&mut *tx, principal, addressbook_id, use_trashbin).await?;
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Some(addressbook) = addressbook
|
if let Some(addressbook) = addressbook {
|
||||||
&& let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(CollectionOperationInfo::Delete, addressbook.push_topic);
|
||||||
data: CollectionOperationInfo::Delete,
|
|
||||||
topic: addressbook.push_topic,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
error!("Push notification about deleted addressbook failed: {err}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -588,7 +634,7 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
|
|
||||||
Self::_put_object(&mut *tx, &principal, &addressbook_id, &object, overwrite).await?;
|
Self::_put_object(&mut *tx, &principal, &addressbook_id, &object, overwrite).await?;
|
||||||
|
|
||||||
let sync_token = log_object_operation(
|
let sync_token = Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&principal,
|
&principal,
|
||||||
&addressbook_id,
|
&addressbook_id,
|
||||||
@@ -600,15 +646,12 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
|
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_addressbook(&principal, &addressbook_id, false)
|
||||||
.get_addressbook(&principal, &addressbook_id, false)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about deleted addressbook failed: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -629,7 +672,7 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
|
|
||||||
Self::_delete_object(&mut *tx, principal, addressbook_id, object_id, use_trashbin).await?;
|
Self::_delete_object(&mut *tx, principal, addressbook_id, object_id, use_trashbin).await?;
|
||||||
|
|
||||||
let sync_token = log_object_operation(
|
let sync_token = Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
principal,
|
principal,
|
||||||
addressbook_id,
|
addressbook_id,
|
||||||
@@ -641,15 +684,12 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
|
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_addressbook(principal, addressbook_id, false)
|
||||||
.get_addressbook(principal, addressbook_id, false)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about deleted addressbook failed: {err}");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +708,7 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
|
|
||||||
Self::_restore_object(&mut *tx, principal, addressbook_id, object_id).await?;
|
Self::_restore_object(&mut *tx, principal, addressbook_id, object_id).await?;
|
||||||
|
|
||||||
let sync_token = log_object_operation(
|
let sync_token = Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
principal,
|
principal,
|
||||||
addressbook_id,
|
addressbook_id,
|
||||||
@@ -679,15 +719,12 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
.map_err(crate::Error::from)?;
|
.map_err(crate::Error::from)?;
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_addressbook(principal, addressbook_id, false)
|
||||||
.get_addressbook(principal, addressbook_id, false)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about restored addressbook object failed: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -732,7 +769,7 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
sync_token = Some(
|
sync_token = Some(
|
||||||
log_object_operation(
|
Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&addressbook.principal,
|
&addressbook.principal,
|
||||||
&addressbook.id,
|
&addressbook.id,
|
||||||
@@ -744,59 +781,14 @@ impl AddressbookStore for SqliteAddressbookStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
if let Some(sync_token) = sync_token
|
if let Some(sync_token) = sync_token {
|
||||||
&& let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_addressbook(&addressbook.principal, &addressbook.id, true)
|
||||||
.get_addressbook(&addressbook.principal, &addressbook.id, true)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
})
|
);
|
||||||
{
|
|
||||||
error!("Push notification about imported addressbook failed: {err}");
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logs an operation to an address object
|
|
||||||
async fn log_object_operation(
|
|
||||||
tx: &mut Transaction<'_, Sqlite>,
|
|
||||||
principal: &str,
|
|
||||||
addressbook_id: &str,
|
|
||||||
object_id: &str,
|
|
||||||
operation: ChangeOperation,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
struct Synctoken {
|
|
||||||
synctoken: i64,
|
|
||||||
}
|
|
||||||
let Synctoken { synctoken } = sqlx::query_as!(
|
|
||||||
Synctoken,
|
|
||||||
r#"
|
|
||||||
UPDATE addressbooks
|
|
||||||
SET synctoken = synctoken + 1
|
|
||||||
WHERE (principal, id) = (?1, ?2)
|
|
||||||
RETURNING synctoken"#,
|
|
||||||
principal,
|
|
||||||
addressbook_id
|
|
||||||
)
|
|
||||||
.fetch_one(&mut **tx)
|
|
||||||
.await
|
|
||||||
.map_err(crate::Error::from)?;
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO addressobjectchangelog (principal, addressbook_id, object_id, "operation", synctoken)
|
|
||||||
VALUES (?1, ?2, ?3, ?4, (
|
|
||||||
SELECT synctoken FROM addressbooks WHERE (principal, id) = (?1, ?2)
|
|
||||||
))"#,
|
|
||||||
principal,
|
|
||||||
addressbook_id,
|
|
||||||
object_id,
|
|
||||||
operation
|
|
||||||
)
|
|
||||||
.execute(&mut **tx)
|
|
||||||
.await
|
|
||||||
.map_err(crate::Error::from)?;
|
|
||||||
Ok(format_synctoken(synctoken))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rustical_store::{CollectionOperation, CollectionOperationInfo};
|
|||||||
use sqlx::types::chrono::NaiveDateTime;
|
use sqlx::types::chrono::NaiveDateTime;
|
||||||
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};
|
use sqlx::{Acquire, Executor, Sqlite, SqlitePool, Transaction};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tracing::{error, instrument, warn};
|
use tracing::{error_span, instrument, warn};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct CalendarObjectRow {
|
struct CalendarObjectRow {
|
||||||
@@ -94,6 +94,57 @@ pub struct SqliteCalendarStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SqliteCalendarStore {
|
impl SqliteCalendarStore {
|
||||||
|
// Logs an operation to the events
|
||||||
|
async fn log_object_operation(
|
||||||
|
tx: &mut Transaction<'_, Sqlite>,
|
||||||
|
principal: &str,
|
||||||
|
cal_id: &str,
|
||||||
|
object_id: &str,
|
||||||
|
operation: ChangeOperation,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
struct Synctoken {
|
||||||
|
synctoken: i64,
|
||||||
|
}
|
||||||
|
let Synctoken { synctoken } = sqlx::query_as!(
|
||||||
|
Synctoken,
|
||||||
|
r#"
|
||||||
|
UPDATE calendars
|
||||||
|
SET synctoken = synctoken + 1
|
||||||
|
WHERE (principal, id) = (?1, ?2)
|
||||||
|
RETURNING synctoken"#,
|
||||||
|
principal,
|
||||||
|
cal_id
|
||||||
|
)
|
||||||
|
.fetch_one(&mut **tx)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO calendarobjectchangelog (principal, cal_id, object_id, "operation", synctoken)
|
||||||
|
VALUES (?1, ?2, ?3, ?4, (
|
||||||
|
SELECT synctoken FROM calendars WHERE (principal, id) = (?1, ?2)
|
||||||
|
))"#,
|
||||||
|
principal,
|
||||||
|
cal_id,
|
||||||
|
object_id,
|
||||||
|
operation
|
||||||
|
)
|
||||||
|
.execute(&mut **tx)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::from)?;
|
||||||
|
Ok(format_synctoken(synctoken))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_push_notification(&self, data: CollectionOperationInfo, topic: String) {
|
||||||
|
if let Err(err) = self.sender.try_send(CollectionOperation { topic, data }) {
|
||||||
|
error_span!(
|
||||||
|
"Error trying to send calendar update notification:",
|
||||||
|
err = format!("{err:?}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Commit "orphaned" objects to the changelog table
|
// Commit "orphaned" objects to the changelog table
|
||||||
pub async fn repair_orphans(&self) -> Result<(), Error> {
|
pub async fn repair_orphans(&self) -> Result<(), Error> {
|
||||||
struct Row {
|
struct Row {
|
||||||
@@ -134,7 +185,8 @@ impl SqliteCalendarStore {
|
|||||||
"Commiting orphaned calendar object ({},{},{}), deleted={}",
|
"Commiting orphaned calendar object ({},{},{}), deleted={}",
|
||||||
&row.principal, &row.cal_id, &row.id, &row.deleted
|
&row.principal, &row.cal_id, &row.id, &row.deleted
|
||||||
);
|
);
|
||||||
log_object_operation(&mut tx, &row.principal, &row.cal_id, &row.id, operation).await?;
|
Self::log_object_operation(&mut tx, &row.principal, &row.cal_id, &row.id, operation)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
@@ -605,13 +657,8 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
Self::_delete_calendar(&mut *tx, principal, id, use_trashbin).await?;
|
Self::_delete_calendar(&mut *tx, principal, id, use_trashbin).await?;
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Some(cal) = cal
|
if let Some(cal) = cal {
|
||||||
&& let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(CollectionOperationInfo::Delete, cal.push_topic);
|
||||||
data: CollectionOperationInfo::Delete,
|
|
||||||
topic: cal.push_topic,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
error!("Push notification about deleted calendar failed: {err}");
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -652,7 +699,7 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
Self::_put_object(&mut *tx, &calendar.principal, &calendar.id, &object, false).await?;
|
Self::_put_object(&mut *tx, &calendar.principal, &calendar.id, &object, false).await?;
|
||||||
|
|
||||||
sync_token = Some(
|
sync_token = Some(
|
||||||
log_object_operation(
|
Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&calendar.principal,
|
&calendar.principal,
|
||||||
&calendar.id,
|
&calendar.id,
|
||||||
@@ -665,16 +712,13 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
|
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Some(sync_token) = sync_token
|
if let Some(sync_token) = sync_token {
|
||||||
&& let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_calendar(&calendar.principal, &calendar.id, true)
|
||||||
.get_calendar(&calendar.principal, &calendar.id, true)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
})
|
);
|
||||||
{
|
|
||||||
error!("Push notification about imported calendar failed: {err}");
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -755,7 +799,7 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
|
|
||||||
Self::_put_object(&mut *tx, &principal, &cal_id, &object, overwrite).await?;
|
Self::_put_object(&mut *tx, &principal, &cal_id, &object, overwrite).await?;
|
||||||
|
|
||||||
let sync_token = log_object_operation(
|
let sync_token = Self::log_object_operation(
|
||||||
&mut tx,
|
&mut tx,
|
||||||
&principal,
|
&principal,
|
||||||
&cal_id,
|
&cal_id,
|
||||||
@@ -766,15 +810,12 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
|
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self
|
self.get_calendar(&principal, &cal_id, true)
|
||||||
.get_calendar(&principal, &cal_id, true)
|
|
||||||
.await?
|
.await?
|
||||||
.push_topic,
|
.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about deleted calendar failed: {err}");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,15 +836,15 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
Self::_delete_object(&mut *tx, principal, cal_id, id, use_trashbin).await?;
|
Self::_delete_object(&mut *tx, principal, cal_id, id, use_trashbin).await?;
|
||||||
|
|
||||||
let sync_token =
|
let sync_token =
|
||||||
log_object_operation(&mut tx, principal, cal_id, id, ChangeOperation::Delete).await?;
|
Self::log_object_operation(&mut tx, principal, cal_id, id, ChangeOperation::Delete)
|
||||||
|
.await?;
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self.get_calendar(principal, cal_id, true).await?.push_topic,
|
self.get_calendar(principal, cal_id, true).await?.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about deleted calendar failed: {err}");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -823,16 +864,14 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
Self::_restore_object(&mut *tx, principal, cal_id, object_id).await?;
|
Self::_restore_object(&mut *tx, principal, cal_id, object_id).await?;
|
||||||
|
|
||||||
let sync_token =
|
let sync_token =
|
||||||
log_object_operation(&mut tx, principal, cal_id, object_id, ChangeOperation::Add)
|
Self::log_object_operation(&mut tx, principal, cal_id, object_id, ChangeOperation::Add)
|
||||||
.await?;
|
.await?;
|
||||||
tx.commit().await.map_err(crate::Error::from)?;
|
tx.commit().await.map_err(crate::Error::from)?;
|
||||||
|
|
||||||
if let Err(err) = self.sender.try_send(CollectionOperation {
|
self.send_push_notification(
|
||||||
data: CollectionOperationInfo::Content { sync_token },
|
CollectionOperationInfo::Content { sync_token },
|
||||||
topic: self.get_calendar(principal, cal_id, true).await?.push_topic,
|
self.get_calendar(principal, cal_id, true).await?.push_topic,
|
||||||
}) {
|
);
|
||||||
error!("Push notification about restored calendar object failed: {err}");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,46 +889,3 @@ impl CalendarStore for SqliteCalendarStore {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logs an operation to the events
|
|
||||||
// TODO: Log multiple updates
|
|
||||||
async fn log_object_operation(
|
|
||||||
tx: &mut Transaction<'_, Sqlite>,
|
|
||||||
principal: &str,
|
|
||||||
cal_id: &str,
|
|
||||||
object_id: &str,
|
|
||||||
operation: ChangeOperation,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
struct Synctoken {
|
|
||||||
synctoken: i64,
|
|
||||||
}
|
|
||||||
let Synctoken { synctoken } = sqlx::query_as!(
|
|
||||||
Synctoken,
|
|
||||||
r#"
|
|
||||||
UPDATE calendars
|
|
||||||
SET synctoken = synctoken + 1
|
|
||||||
WHERE (principal, id) = (?1, ?2)
|
|
||||||
RETURNING synctoken"#,
|
|
||||||
principal,
|
|
||||||
cal_id
|
|
||||||
)
|
|
||||||
.fetch_one(&mut **tx)
|
|
||||||
.await
|
|
||||||
.map_err(crate::Error::from)?;
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO calendarobjectchangelog (principal, cal_id, object_id, "operation", synctoken)
|
|
||||||
VALUES (?1, ?2, ?3, ?4, (
|
|
||||||
SELECT synctoken FROM calendars WHERE (principal, id) = (?1, ?2)
|
|
||||||
))"#,
|
|
||||||
principal,
|
|
||||||
cal_id,
|
|
||||||
object_id,
|
|
||||||
operation
|
|
||||||
)
|
|
||||||
.execute(&mut **tx)
|
|
||||||
.await
|
|
||||||
.map_err(crate::Error::from)?;
|
|
||||||
Ok(format_synctoken(synctoken))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl SubscriptionStore for SqliteStore {
|
|||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
};
|
};
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"INSERT OR REPLACE INTO davpush_subscriptions (id, topic, expiration, push_resource, public_key, public_key_type, auth_secret) VALUES (?, ?, ?, ?, ?, ?, ?)"#,
|
r#"REPLACE INTO davpush_subscriptions (id, topic, expiration, push_resource, public_key, public_key_type, auth_secret) VALUES (?, ?, ?, ?, ?, ?, ?)"#,
|
||||||
sub.id,
|
sub.id,
|
||||||
sub.topic,
|
sub.topic,
|
||||||
sub.expiration,
|
sub.expiration,
|
||||||
|
|||||||
Reference in New Issue
Block a user