summaryrefslogtreecommitdiff
path: root/src/channel/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/channel/app.rs')
-rw-r--r--src/channel/app.rs65
1 files changed, 42 insertions, 23 deletions
diff --git a/src/channel/app.rs b/src/channel/app.rs
index 8359277..21784e9 100644
--- a/src/channel/app.rs
+++ b/src/channel/app.rs
@@ -4,13 +4,13 @@ use sqlx::sqlite::SqlitePool;
use super::{
repo::{LoadError, Provider as _},
- Channel, Id,
+ validate, Channel, Id,
};
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},
};
@@ -25,6 +25,10 @@ impl<'a> Channels<'a> {
}
pub async fn create(&self, name: &Name, created_at: &DateTime) -> Result<Channel, CreateError> {
+ if !validate::name(name) {
+ return Err(CreateError::InvalidName(name.clone()));
+ }
+
let mut tx = self.db.begin().await?;
let created = tx.sequence().next(created_at).await?;
let channel = tx
@@ -44,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?;
@@ -135,20 +137,14 @@ impl<'a> Channels<'a> {
Ok(())
}
-
- pub async fn recanonicalize(&self) -> Result<(), sqlx::Error> {
- let mut tx = self.db.begin().await?;
- tx.channels().recanonicalize().await?;
- tx.commit().await?;
-
- Ok(())
- }
}
#[derive(Debug, thiserror::Error)]
pub enum CreateError {
#[error("channel named {0} already exists")]
DuplicateName(Name),
+ #[error("invalid channel name: {0}")]
+ InvalidName(Name),
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]
@@ -186,6 +182,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),