You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
4.5 KiB

use std::{error::Error, fmt::Display, time::Duration};
use serde::{Deserialize, Serialize};
use crate::api::FastInsidersApi;
#[cfg(client)]
#[derive(Serialize)]
pub struct UserLoginBody {
pub name: String,
pub password: String,
}
#[cfg(client)]
#[derive(Serialize)]
pub struct UserRegisterBody {
pub name: String,
pub email: String,
pub password: String,
}
#[cfg(client)]
type Response = reqwasm::http::Response;
#[cfg(client)]
#[derive(Deserialize)]
struct LoginResponse {
pub token: String,
}
#[cfg(client)]
#[derive(Debug, Deserialize)]
pub enum LoginError {
Unknown,
InvalidCredentials,
InternalServer(String),
Server(String),
UserNotFound(String),
}
#[cfg(client)]
#[derive(Deserialize)]
struct ErrorBody {
error: String,
}
#[cfg(client)]
impl Display for LoginError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unknown => {
write!(f, "There was an unknown error while trying to log you in.").to_owned()
}
Self::InternalServer(e) => write!(f, "Internal server error: {}", e),
Self::Server(e) => write!(f, "There was an error completing the request {}", e),
Self::InvalidCredentials => write!(f, "Invalid username or password"),
Self::UserNotFound(e) => write!(f, "{e}"),
}
}
}
#[cfg(client)]
impl Error for LoginError {}
#[cfg(client)]
#[derive(Debug, Deserialize)]
pub enum RegisterError {
Unknown,
InternalServer(String),
Server(String),
Conflict(String),
}
#[cfg(client)]
impl Display for RegisterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unknown => {
write!(f, "There was an unknown error while trying to log you in.").to_owned()
}
Self::InternalServer(e) => write!(f, "Internal server error: {}", e),
Self::Server(e) => write!(f, "There was an error completing the request {}", e),
Self::Conflict(e) => write!(f, "{e}"),
}
}
}
#[cfg(client)]
impl Error for RegisterError {}
#[cfg(client)]
pub fn set_token_cookie(token: &str) {
use wasm_cookies::CookieOptions;
let cookie_options = CookieOptions::default()
.secure()
.with_same_site(wasm_cookies::SameSite::Strict)
.expires_after(Duration::from_secs(60 * 60 * 24 * 5)); // 5 days
wasm_cookies::set("token", token, &cookie_options);
}
#[cfg(client)]
impl FastInsidersApi {
pub async fn login(&self, body: &UserLoginBody) -> Result<(), LoginError> {
let route = &format!("{}/user/login", self.url);
let resp = reqwasm::http::Request::post(route)
.header("Content-type", "application/json")
.body(serde_json::to_string(&body).unwrap())
.send()
.await
.map_err(|e| LoginError::Server(e.to_string()))?;
if resp.status() == 200 {
if let Ok(data) = resp.json::<LoginResponse>().await {
set_token_cookie(&data.token);
return Ok(());
} else {
panic!();
}
}
match resp.status() {
401 => return Err(LoginError::InvalidCredentials),
500 => {
let error = resp.json::<ErrorBody>().await.unwrap().error;
return Err(LoginError::InternalServer(error));
}
404 => {
let error = resp.json::<ErrorBody>().await.unwrap().error;
return Err(LoginError::UserNotFound(error));
}
_ => return Err(LoginError::Unknown),
}
}
pub async fn register(&self, body: &UserRegisterBody) -> Result<(), RegisterError> {
let route = &format!("{}/user/register", self.url);
use wasm_cookies::CookieOptions;
let resp = reqwasm::http::Request::post(route)
.header("Content-type", "application/json")
.body(serde_json::to_string(&body).unwrap())
.send()
.await
.map_err(|e| RegisterError::Server(e.to_string()))?;
if resp.status() == 200 {
return Ok(());
}
if resp.status() == 500 {
let error = resp.json::<ErrorBody>().await.unwrap().error;
return Err(RegisterError::InternalServer(error));
}
if resp.status() == 409 {
let error = resp.json::<ErrorBody>().await.unwrap().error;
return Err(RegisterError::Conflict(error));
}
Err(RegisterError::Unknown)
}
}