summaryrefslogtreecommitdiff
path: root/src/channel/app.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-10-30 01:07:12 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-10-30 01:07:12 -0400
commit36e659e971d091cfcbe370f5e45a0d01102d2e83 (patch)
treeb820f037590d9923ef8cbe8d8a2a9d73b4ed1be6 /src/channel/app.rs
parent2bac295504960ac4a18d7c19513160363f587f01 (diff)
Prevent deletion of non-empty channels.
Diffstat (limited to 'src/channel/app.rs')
-rw-r--r--src/channel/app.rs49
1 files changed, 35 insertions, 14 deletions
diff --git a/src/channel/app.rs b/src/channel/app.rs
index 9a19b16..e32eb6c 100644
--- a/src/channel/app.rs
+++ b/src/channel/app.rs
@@ -10,7 +10,7 @@ use crate::{
clock::DateTime,
db::{Duplicate as _, NotFound as _},
event::{repo::Provider as _, Broadcaster, Event, Sequence},
- message::repo::Provider as _,
+ message::{self, repo::Provider as _},
name::{self, Name},
};
@@ -48,38 +48,36 @@ impl<'a> Channels<'a> {
// it exists in the specific moment when you call it.
pub async fn get(&self, channel: &Id) -> Result<Channel, Error> {
let not_found = || Error::NotFound(channel.clone());
+ let deleted = || Error::Deleted(channel.clone());
let mut tx = self.db.begin().await?;
let channel = tx.channels().by_id(channel).await.not_found(not_found)?;
tx.commit().await?;
- channel.as_snapshot().ok_or_else(not_found)
+ channel.as_snapshot().ok_or_else(deleted)
}
- pub async fn delete(&self, channel: &Id, deleted_at: &DateTime) -> Result<(), Error> {
+ pub async fn delete(&self, channel: &Id, deleted_at: &DateTime) -> Result<(), DeleteError> {
let mut tx = self.db.begin().await?;
let channel = tx
.channels()
.by_id(channel)
.await
- .not_found(|| Error::NotFound(channel.clone()))?;
+ .not_found(|| DeleteError::NotFound(channel.clone()))?;
channel
.as_snapshot()
- .ok_or_else(|| Error::Deleted(channel.id().clone()))?;
+ .ok_or_else(|| DeleteError::Deleted(channel.id().clone()))?;
let mut events = Vec::new();
let messages = tx.messages().live(&channel).await?;
- for message in messages {
- let deleted = tx.sequence().next(deleted_at).await?;
- let message = tx.messages().delete(&message, &deleted).await?;
- events.extend(
- message
- .events()
- .filter(Sequence::start_from(deleted.sequence))
- .map(Event::from),
- );
+ let has_messages = messages
+ .iter()
+ .map(message::History::as_snapshot)
+ .any(|message| message.is_some());
+ if has_messages {
+ return Err(DeleteError::NotEmpty(channel.id().clone()));
}
let deleted = tx.sequence().next(deleted_at).await?;
@@ -192,6 +190,29 @@ impl From<LoadError> for Error {
}
#[derive(Debug, thiserror::Error)]
+pub enum DeleteError {
+ #[error("channel {0} not found")]
+ NotFound(Id),
+ #[error("channel {0} deleted")]
+ Deleted(Id),
+ #[error("channel {0} not empty")]
+ NotEmpty(Id),
+ #[error(transparent)]
+ Database(#[from] sqlx::Error),
+ #[error(transparent)]
+ Name(#[from] name::Error),
+}
+
+impl From<LoadError> for DeleteError {
+ fn from(error: LoadError) -> Self {
+ match error {
+ LoadError::Database(error) => error.into(),
+ LoadError::Name(error) => error.into(),
+ }
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
pub enum ExpireError {
#[error(transparent)]
Database(#[from] sqlx::Error),