diff options
Diffstat (limited to 'src/invite')
| -rw-r--r-- | src/invite/app.rs | 50 | ||||
| -rw-r--r-- | src/invite/handlers/accept/test.rs | 28 | ||||
| -rw-r--r-- | src/invite/handlers/issue/mod.rs | 2 | ||||
| -rw-r--r-- | src/invite/handlers/issue/test.rs | 2 | ||||
| -rw-r--r-- | src/invite/repo.rs | 3 |
5 files changed, 57 insertions, 28 deletions
diff --git a/src/invite/app.rs b/src/invite/app.rs index 1c85562..6684d03 100644 --- a/src/invite/app.rs +++ b/src/invite/app.rs @@ -5,13 +5,15 @@ use super::{Id, Invite, Summary, repo::Provider as _}; use crate::{ clock::DateTime, db::{Duplicate as _, NotFound as _}, - event::Broadcaster, - name::Name, + event::{Broadcaster, repo::Provider as _}, + login::Login, + name::{self, Name}, password::Password, - token::{Secret, repo::Provider as _}, + token::{Secret, Token, repo::Provider as _}, user::{ - User, + self, create::{self, Create}, + repo::{LoadError, Provider as _}, }, }; @@ -25,9 +27,19 @@ impl<'a> Invites<'a> { Self { db, events } } - pub async fn issue(&self, issuer: &User, issued_at: &DateTime) -> Result<Invite, sqlx::Error> { + pub async fn issue(&self, issuer: &Login, issued_at: &DateTime) -> Result<Invite, Error> { + let issuer_not_found = || Error::IssuerNotFound(issuer.id.clone().into()); + let issuer_deleted = || Error::IssuerDeleted(issuer.id.clone().into()); + let mut tx = self.db.begin().await?; - let invite = tx.invites().create(issuer, issued_at).await?; + let issuer = tx + .users() + .by_login(issuer) + .await + .not_found(issuer_not_found)?; + let now = tx.sequence().current().await?; + let issuer = issuer.as_of(now).ok_or_else(issuer_deleted)?; + let invite = tx.invites().create(&issuer, issued_at).await?; tx.commit().await?; Ok(invite) @@ -71,7 +83,9 @@ impl<'a> Invites<'a> { .store(&mut tx) .await .duplicate(|| AcceptError::DuplicateLogin(name.clone()))?; - let secret = tx.tokens().issue(stored.user(), accepted_at).await?; + let login = stored.login(); + let (token, secret) = Token::generate(login, accepted_at); + tx.tokens().create(&token, &secret).await?; tx.commit().await?; stored.publish(self.events); @@ -92,6 +106,28 @@ impl<'a> Invites<'a> { } #[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("issuing user {0} not found")] + IssuerNotFound(user::Id), + #[error("issuing user {0} deleted")] + IssuerDeleted(user::Id), + #[error(transparent)] + Database(#[from] sqlx::Error), + #[error(transparent)] + Name(#[from] name::Error), +} + +impl From<user::repo::LoadError> for Error { + fn from(error: LoadError) -> Self { + use user::repo::LoadError; + match error { + LoadError::Database(error) => error.into(), + LoadError::Name(error) => error.into(), + } + } +} + +#[derive(Debug, thiserror::Error)] pub enum AcceptError { #[error("invite not found: {0}")] NotFound(Id), diff --git a/src/invite/handlers/accept/test.rs b/src/invite/handlers/accept/test.rs index adc7aa4..283ec76 100644 --- a/src/invite/handlers/accept/test.rs +++ b/src/invite/handlers/accept/test.rs @@ -1,6 +1,11 @@ use axum::extract::{Json, Path, State}; -use crate::{empty::Empty, invite::app::AcceptError, name::Name, test::fixtures}; +use crate::{ + empty::Empty, + invite::app::AcceptError, + name::Name, + test::{fixtures, verify}, +}; #[tokio::test] async fn valid_invite() { @@ -34,29 +39,16 @@ async fn valid_invite() { // Verify that the issued token is valid - let secret = identity - .secret() - .expect("newly-issued identity has a token secret"); - let (_, login) = app - .tokens() - .validate(&secret, &fixtures::now()) - .await - .expect("newly-issued identity cookie is valid"); - assert_eq!(name, login.name); + verify::identity::valid_for_name(&app, &identity, &name).await; // Verify that the given credentials can log in let secret = app - .tokens() - .login(&name, &password, &fixtures::now()) + .logins() + .with_password(&name, &password, &fixtures::now()) .await .expect("credentials given on signup are valid"); - let (_, login) = app - .tokens() - .validate(&secret, &fixtures::now()) - .await - .expect("validating a newly-issued token secret succeeds"); - assert_eq!(name, login.name); + verify::token::valid_for_name(&app, &secret, &name).await; } #[tokio::test] diff --git a/src/invite/handlers/issue/mod.rs b/src/invite/handlers/issue/mod.rs index 6085f7a..4ac74cc 100644 --- a/src/invite/handlers/issue/mod.rs +++ b/src/invite/handlers/issue/mod.rs @@ -13,7 +13,7 @@ pub async fn handler( identity: Identity, _: Json<Request>, ) -> Result<Json<Invite>, Internal> { - let invite = app.invites().issue(&identity.user, &issued_at).await?; + let invite = app.invites().issue(&identity.login, &issued_at).await?; Ok(Json(invite)) } diff --git a/src/invite/handlers/issue/test.rs b/src/invite/handlers/issue/test.rs index 2bf5400..4421705 100644 --- a/src/invite/handlers/issue/test.rs +++ b/src/invite/handlers/issue/test.rs @@ -22,6 +22,6 @@ async fn create_invite() { .expect("creating an invite always succeeds"); // Verify the response - assert_eq!(issuer.user.id, invite.issuer); + assert_eq!(issuer.login.id, invite.issuer); assert_eq!(&*issued_at, &invite.issued_at); } diff --git a/src/invite/repo.rs b/src/invite/repo.rs index 7cfa18e..934b0ce 100644 --- a/src/invite/repo.rs +++ b/src/invite/repo.rs @@ -71,10 +71,11 @@ impl Invites<'_> { select invite.id as "invite_id: Id", issuer.id as "issuer_id: user::Id", - issuer.display_name as "issuer_name: nfc::String", + issuer_login.display_name as "issuer_name: nfc::String", invite.issued_at as "invite_issued_at: DateTime" from invite join user as issuer on (invite.issuer = issuer.id) + join login as issuer_login on (issuer.id = issuer_login.id) where invite.id = $1 "#, invite, |
