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! {
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>;
}
#[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),
}