etwin_core 0.12.3

Core crate for Eternal-Twin
Documentation
use crate::core::Instant;
use crate::email::EmailAddress;
use crate::link::VersionedEtwinLink;
use crate::oauth::RfcOauthAccessTokenKey;
use crate::types::AnyError;
use async_trait::async_trait;
use auto_impl::auto_impl;
#[cfg(feature = "serde")]
use etwin_serde_tools::{Deserialize, Serialize};
use thiserror::Error;

declare_decimal_id! {
  pub struct TwinoidUserId(u32);
  pub type ParseError = TwinoidUserIdParseError;
  const BOUNDS = 1..1_000_000_000;
  const SQL_NAME = "twinoid_user_id";
}

impl TwinoidUserId {
  pub fn as_ref(self) -> TwinoidUserIdRef {
    TwinoidUserIdRef { id: self }
  }
}

declare_new_string! {
  pub struct TwinoidUserDisplayName(String);
  pub type ParseError = TwinoidUserDisplayNameParseError;
  const PATTERN = r"^.{1,100}$";
  const SQL_NAME = "twinoid_user_display_name";
}

declare_new_string! {
  /// A Twinoid session key.
  ///
  /// It correspond to the value of the `tw_sid` cookie.
  ///
  /// - `LuTuRdIOmZU4JVOt7U70bQzEzzSlkAG2`
  pub struct TwinoidSessionKey(String);
  pub type ParseError = TwinoidSessionKeyParseError;
  const PATTERN = r"^[0-9a-zA-Z]{32}$";
  const SQL_NAME = "twinoid_session_key";
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "TwinoidUser"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ShortTwinoidUser {
  pub id: TwinoidUserId,
  pub display_name: TwinoidUserDisplayName,
}

impl ShortTwinoidUser {
  pub fn as_ref(&self) -> TwinoidUserIdRef {
    TwinoidUserIdRef { id: self.id }
  }
}

impl From<ArchivedTwinoidUser> for ShortTwinoidUser {
  fn from(value: ArchivedTwinoidUser) -> Self {
    Self {
      id: value.id,
      display_name: value.display_name,
    }
  }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "TwinoidUser"))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TwinoidUserIdRef {
  pub id: TwinoidUserId,
}

impl From<TwinoidUserId> for TwinoidUserIdRef {
  fn from(id: TwinoidUserId) -> Self {
    Self { id }
  }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "TwinoidUser"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArchivedTwinoidUser {
  pub id: TwinoidUserId,
  pub archived_at: Instant,
  pub display_name: TwinoidUserDisplayName,
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "TwinoidUser"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EtwinTwinoidUser {
  pub id: TwinoidUserId,
  pub archived_at: Instant,
  pub display_name: TwinoidUserDisplayName,
  pub etwin: VersionedEtwinLink,
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetTwinoidUserOptions {
  pub id: TwinoidUserId,
  pub time: Option<Instant>,
}

#[async_trait]
#[auto_impl(&, Arc)]
pub trait TwinoidStore: Send + Sync {
  async fn get_short_user(&self, options: &GetTwinoidUserOptions) -> Result<Option<ShortTwinoidUser>, AnyError>;

  async fn get_user(&self, options: &GetTwinoidUserOptions) -> Result<Option<ArchivedTwinoidUser>, AnyError>;

  async fn touch_short_user(&self, options: &ShortTwinoidUser) -> Result<ArchivedTwinoidUser, AnyError>;
}

// #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TwinoidApiAuth {
  Guest,
  Token(RfcOauthAccessTokenKey),
}

pub mod api {
  use crate::core::HtmlFragment;
  use crate::twinoid::TwinoidUserDisplayName;
  #[cfg(feature = "serde")]
  use etwin_serde_tools::{Deserialize, Serialize};

  #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
  #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
  pub struct User {
    pub id: u32,
    pub name: TwinoidUserDisplayName,
    pub title: Option<HtmlFragment>,
  }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TwinoidPassword(String);

impl TwinoidPassword {
  pub fn new(raw: String) -> Self {
    Self(raw)
  }

  pub fn as_str(&self) -> &str {
    &self.0
  }
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TwinoidCredentials {
  pub email: EmailAddress,
  pub password: TwinoidPassword,
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TwinoidSession {
  pub key: TwinoidSessionKey,
  pub user: ShortTwinoidUser,
}

#[async_trait]
#[auto_impl(&, Arc)]
pub trait TwinoidClient: Send + Sync {
  async fn get_me_short(&self, auth: TwinoidApiAuth) -> Result<api::User, AnyError>;

  async fn create_session(
    &self,
    options: &TwinoidCredentials,
  ) -> Result<TwinoidSession, TwinoidClientCreateSessionError>;
}

#[derive(Debug, Error)]
pub enum TwinoidClientCreateSessionError {
  #[error("wrong credentials")]
  WrongCredentials,
  #[error(transparent)]
  Other(#[from] AnyError),
}