use crate::error::Result;
use async_trait::async_trait;
#[cfg(any(test, feature = "organizations-seaorm", feature = "test-organizations"))]
use sha2::{Digest, Sha256};
#[cfg(any(test, feature = "organizations-seaorm", feature = "test-organizations"))]
pub(crate) fn hash_invitation_token(token: &str) -> String {
format!("{:x}", Sha256::digest(token.as_bytes()))
}
#[async_trait]
pub trait InvitationStore: Send + Sync {
type Invitation: Send + Sync + Clone;
type Role: Send + Sync + Clone;
async fn create(&self, invitation: &Self::Invitation) -> Result<()>;
async fn find_by_token(&self, token: &str) -> Result<Option<Self::Invitation>>;
async fn claim_pending_by_token(&self, token: &str) -> Result<Option<Self::Invitation>> {
let invitation = self.find_by_token(token).await?;
if let Some(ref invitation) = invitation {
self.mark_processing(&self.invitation_id(invitation))
.await?;
}
Ok(invitation)
}
async fn find_by_id(&self, id: &str) -> Result<Option<Self::Invitation>>;
async fn list_pending(&self, org_id: &str) -> Result<Vec<Self::Invitation>>;
async fn mark_accepted(&self, id: &str) -> Result<()>;
async fn mark_processing(&self, _id: &str) -> Result<()> {
Ok(())
}
async fn release_claim(&self, _id: &str) -> Result<()> {
Ok(())
}
async fn mark_revoked(&self, id: &str) -> Result<()>;
async fn delete_expired(&self) -> Result<usize>;
fn invitation_id(&self, inv: &Self::Invitation) -> String;
fn invitation_org_id(&self, inv: &Self::Invitation) -> String;
fn invitation_email(&self, inv: &Self::Invitation) -> String;
fn invitation_role(&self, inv: &Self::Invitation) -> Self::Role;
fn invitation_token(&self, inv: &Self::Invitation) -> String;
fn invitation_expires_at(&self, inv: &Self::Invitation) -> u64;
fn is_expired(&self, inv: &Self::Invitation) -> bool;
fn is_revoked(&self, inv: &Self::Invitation) -> bool;
async fn find_pending_by_email(
&self,
org_id: &str,
email: &str,
) -> Result<Option<Self::Invitation>> {
let pending = self.list_pending(org_id).await?;
Ok(pending
.into_iter()
.find(|i| self.invitation_email(i) == email))
}
async fn count_pending(&self, org_id: &str) -> Result<u32> {
Ok(self.list_pending(org_id).await?.len() as u32)
}
}