use std::cell::Cell;
use crate::user::SessionUser;
use crate::{Authenticated, Backend, User, ValidPassword};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(
feature = "postgres",
derive(postgres_types::ToSql, postgres_types::FromSql)
)]
pub struct SessionId(pub uuid::Uuid);
impl SessionId {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(uuid::Uuid::new_v4())
}
}
impl std::str::FromStr for SessionId {
type Err = uuid::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(uuid::Uuid::parse_str(s)?))
}
}
#[derive(Debug)]
pub struct SessionFields<B: Backend> {
pub user_id: Option<<B::User as User>::Id>,
pub data: B::SessionData,
}
pub struct Session<B: Backend> {
pub backend: B,
pub data: B::SessionData,
id: SessionId,
pub(crate) user: SessionUser<B::User>,
needs_save: Cell<bool>,
}
impl<B: Backend> Session<B> {
pub fn new(
backend: B,
id: SessionId,
user_id: Option<<B::User as User>::Id>,
data: B::SessionData,
) -> Self {
Self {
backend,
id,
data,
user: SessionUser::new(user_id),
needs_save: Cell::new(false),
}
}
pub fn is_authenticated(&self) -> bool {
self.user.is_authenticated()
}
pub async fn user(&self) -> Result<Option<&B::User>, B::Error> {
self.user.user(&self.backend).await
}
pub async fn user_mut(&mut self) -> Result<Option<&mut B::User>, B::Error> {
self.user.user_mut(&self.backend).await
}
pub(crate) fn set_user_id(
&mut self,
user_id: Option<<B::User as User>::Id>,
) {
if user_id.as_ref() != self.user.id() {
self.needs_save();
}
self.user.set_id(user_id);
}
pub(crate) fn set_user(&mut self, user: Option<B::User>) {
if user.as_ref().map(|user| user.id()) != self.user.id() {
self.needs_save();
}
self.user.set_user(user);
}
pub fn needs_save(&self) {
self.needs_save.set(true);
}
pub async fn save(&self) -> Result<(), B::Error> {
if self.needs_save.get() {
self.force_save().await?;
}
Ok(())
}
pub async fn force_save(&self) -> Result<(), B::Error> {
self.backend
.update_session_data(&self.id, self.user.id(), &self.data)
.await?;
self.needs_save.set(false);
Ok(())
}
pub async fn force_login(
&mut self,
user_id: <B::User as User>::Id,
) -> Result<(), B::Error> {
self.set_user_id(Some(user_id));
Ok(())
}
pub async fn force_login_user(
&mut self,
user: B::User,
) -> Result<(), B::Error> {
self.set_user(Some(user));
Ok(())
}
pub async fn login_by_password(
&mut self,
email: &str,
password: &str,
) -> Result<Option<Authenticated>, B::Error> {
crate::func::login_by_password(self, email, password).await
}
pub async fn logout(&mut self) -> Result<(), B::Error> {
self.set_user(None);
Ok(())
}
pub async fn update_user_password(
&mut self,
password: &ValidPassword,
) -> Result<(), B::Error> {
crate::func::update_user_password(self, password).await
}
}