wrbapp/src/util/model/session.rs

136 lines
3.9 KiB
Rust

#[cfg(feature = "server")]
use crate::util::surrealdb::{thing_to_string, DB};
use dioxus::prelude::*;
use serde::{Deserialize, Serialize};
use super::user::User;
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
pub struct Session {
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
id: String,
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
user_id: String,
expires: i64,
token: String,
}
#[cfg(feature = "server")]
impl Session {
pub async fn new(user_id: String) -> Result<Self, crate::Error> {
let mut res = DB
.query("CREATE ONLY session SET user = type::thing('user', $user_id) RETURN id, user as user_id, time::unix(expires) as expires, token;")
.bind(("user_id", user_id))
.await?;
res = res.check()?;
let session: Option<Self> = res.take(0)?;
match session {
Some(s) => Ok(s),
None => Err(crate::Error::NoDocument),
}
}
pub fn set_cookie(&self) -> Result<(), crate::Error> {
use axum::http::{header, HeaderValue};
use axum_extra::extract::cookie::{Cookie, Expiration, SameSite};
use dioxus::prelude::server_context;
use time::OffsetDateTime;
let timestamp = OffsetDateTime::from_unix_timestamp(self.expires)?;
let expiration = Expiration::from(timestamp);
let mut cookie = Cookie::build(("session_token", &self.token))
.expires(expiration)
.build();
cookie.set_same_site(SameSite::Strict);
server_context()
.response_parts_mut()
.unwrap()
.headers
.insert(
header::SET_COOKIE,
HeaderValue::from_str(&cookie.to_string())?,
);
Ok(())
}
pub async fn fetch_user_from_token(session_token: String) -> Result<User, crate::Error> {
let mut res = DB
.query(
"SELECT user as id, user.email as email, user.admin as admin FROM session WHERE token = $session_token",
)
.bind(("session_token", session_token))
.await?;
res = res.check()?;
let user: Option<User> = res.take(0)?;
match user {
Some(u) => Ok(u),
None => Err(crate::Error::NoDocument),
}
}
pub async fn get_token_from_cookie() -> Result<String, crate::Error> {
use axum_extra::extract::CookieJar;
let jar: CookieJar = extract().await.unwrap_or_default();
match jar.get("session_token") {
Some(s) => Ok(s.value().to_string()),
None => Err(crate::Error::NoSessionCookie),
}
}
pub async fn delete_cookie() -> Result<(), crate::Error> {
use axum::http::{header, HeaderValue};
use axum_extra::extract::cookie::{Cookie, SameSite};
use dioxus::prelude::server_context;
use time::Duration;
let mut cookie = Cookie::build(("session_token", ""))
.max_age(Duration::seconds(1))
.build();
cookie.set_same_site(SameSite::Strict);
server_context()
.response_parts_mut()
.unwrap()
.headers
.insert(
header::SET_COOKIE,
HeaderValue::from_str(&cookie.to_string())?,
);
Ok(())
}
pub async fn delete_session(user_id: String) -> Result<(), crate::Error> {
let res = DB
.query("DELETE ONLY session WHERE user = type::thing('user', $user_id)")
.bind(("user_id", user_id))
.await?;
res.check()?;
Ok(())
}
// Fetches the current user from cookie headers
pub async fn fetch_current_user() -> Result<User, crate::Error> {
let session_token = Self::get_token_from_cookie().await?;
let user = Self::fetch_user_from_token(session_token).await?;
Ok(user)
}
}