summaryrefslogtreecommitdiff
path: root/src/user/app.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-03-23 15:58:33 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-03-23 16:25:22 -0400
commit2420f1e75d54a5f209b0267715f078a369d81eb1 (patch)
tree20edd531a3f2f765a23fef8e7a508c91bc7dc294 /src/user/app.rs
parent7e15690d54ff849596401b43d163df9353062850 (diff)
Rename the `login` module to `user`.
Diffstat (limited to 'src/user/app.rs')
-rw-r--r--src/user/app.rs56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/user/app.rs b/src/user/app.rs
new file mode 100644
index 0000000..2ab356f
--- /dev/null
+++ b/src/user/app.rs
@@ -0,0 +1,56 @@
+use sqlx::sqlite::SqlitePool;
+
+use super::{
+ Password, User,
+ create::{self, Create},
+};
+use crate::{clock::DateTime, event::Broadcaster, name::Name};
+
+pub struct Users<'a> {
+ db: &'a SqlitePool,
+ events: &'a Broadcaster,
+}
+
+impl<'a> Users<'a> {
+ pub const fn new(db: &'a SqlitePool, events: &'a Broadcaster) -> Self {
+ Self { db, events }
+ }
+
+ pub async fn create(
+ &self,
+ name: &Name,
+ password: &Password,
+ created_at: &DateTime,
+ ) -> Result<User, CreateError> {
+ let create = Create::begin(name, password, created_at);
+ let validated = create.validate()?;
+
+ let mut tx = self.db.begin().await?;
+ let stored = validated.store(&mut tx).await?;
+ tx.commit().await?;
+
+ let user = stored.publish(self.events);
+
+ Ok(user.as_created())
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum CreateError {
+ #[error("invalid user name: {0}")]
+ InvalidName(Name),
+ #[error(transparent)]
+ PasswordHash(#[from] password_hash::Error),
+ #[error(transparent)]
+ Database(#[from] sqlx::Error),
+}
+
+#[cfg(test)]
+impl From<create::Error> for CreateError {
+ fn from(error: create::Error) -> Self {
+ match error {
+ create::Error::InvalidName(name) => Self::InvalidName(name),
+ create::Error::PasswordHash(error) => Self::PasswordHash(error),
+ }
+ }
+}