use axum::{response::Response, routing::post, Router}; use serde::Deserialize; use time::{Duration, OffsetDateTime}; use tower_cookies::{Cookie, Cookies}; use crate::types::{ extract::{AuthorizedUser, Check, CheckResult, Json, Log}, http::ResponseCode, session::Session, user::User, }; #[derive(Deserialize, Debug)] pub struct RegistrationRequet { pub firstname: String, pub lastname: String, pub email: String, pub password: String, pub gender: String, pub day: u8, pub month: u8, pub year: u32, } impl Check for RegistrationRequet { fn check(&self) -> CheckResult { Self::assert_length( &self.firstname, 1, 20, "First name can only by 1-20 characters long", )?; Self::assert_length( &self.lastname, 1, 20, "Last name can only by 1-20 characters long", )?; Self::assert_length(&self.email, 1, 50, "Email can only by 1-50 characters long")?; Self::assert_length( &self.password, 1, 50, "Password can only by 1-50 characters long", )?; Self::assert_length( &self.gender, 1, 100, "Gender can only by 1-100 characters long", )?; Self::assert_range( u64::from(self.day), 1, 255, "Birthday day can only be between 1-255", )?; Self::assert_range( u64::from(self.month), 1, 255, "Birthday month can only be between 1-255", )?; Self::assert_range( u64::from(self.year), 1, 4_294_967_295, "Birthday year can only be between 1-4294967295", )?; Ok(()) } } async fn register(cookies: Cookies, Json(body): Json) -> Response { let user = match User::new(body) { Ok(user) => user, Err(err) => return err, }; let session = match Session::new(user.user_id) { Ok(session) => session, Err(err) => return err, }; let mut now = OffsetDateTime::now_utc(); now += Duration::weeks(52); let mut cookie = Cookie::new("auth", session.token); cookie.set_secure(false); cookie.set_http_only(false); cookie.set_expires(now); cookie.set_path("/"); cookies.add(cookie); ResponseCode::Created.text("Successfully created new user") } #[derive(Deserialize)] struct LoginRequest { email: String, password: String, } impl Check for LoginRequest { fn check(&self) -> CheckResult { Ok(()) } } async fn login(cookies: Cookies, Json(body): Json) -> Response { let Ok(user) = User::from_email(&body.email) else { return ResponseCode::BadRequest.text("Email is not registered") }; if user.password != body.password { return ResponseCode::BadRequest.text("Password is not correct"); } let session = match Session::new(user.user_id) { Ok(session) => session, Err(err) => return err, }; let mut now = OffsetDateTime::now_utc(); now += Duration::weeks(52); let mut cookie = Cookie::new("auth", session.token); cookie.set_secure(false); cookie.set_http_only(false); cookie.set_expires(now); cookie.set_path("/"); cookies.add(cookie); ResponseCode::Success.text("Successfully logged in") } async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser, _: Log) -> Response { cookies.remove(Cookie::new("auth", "")); if let Err(err) = Session::delete(user.user_id) { return err; } ResponseCode::Success.text("Successfully logged out") } pub fn router() -> Router { Router::new() .route("/register", post(register)) .route("/login", post(login)) .route("/logout", post(logout)) }