175 lines
4.2 KiB
Rust
175 lines
4.2 KiB
Rust
use crate::{to_cookie_page, to_home, AcceptedCookies, Authenticated, Error, State};
|
|
use actix_session::Session;
|
|
use actix_web::{error::BlockingError, web, HttpResponse};
|
|
|
|
pub type RegisterPageArgs = (
|
|
Option<AcceptedCookies>,
|
|
Option<Authenticated>,
|
|
web::Data<State>,
|
|
);
|
|
|
|
pub type RegisterArgs = (
|
|
Option<AcceptedCookies>,
|
|
Option<Authenticated>,
|
|
web::Data<State>,
|
|
Session,
|
|
web::Form<RegisterForm>,
|
|
);
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
pub struct RegisterForm {
|
|
username: String,
|
|
password: String,
|
|
password_confirmation: String,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RegisterState {
|
|
state: State,
|
|
form: Option<RegisterForm>,
|
|
error: Option<RegisterError>,
|
|
pub(crate) dark: bool,
|
|
}
|
|
|
|
pub fn register_page(
|
|
(cookies, authenticated, state): RegisterPageArgs,
|
|
) -> Result<RegisterState, HttpResponse> {
|
|
if cookies.is_none() {
|
|
return Err(to_cookie_page(&state));
|
|
}
|
|
|
|
if authenticated.is_some() {
|
|
return Err(to_home(&state));
|
|
}
|
|
|
|
Ok(RegisterState::new_empty(&state))
|
|
}
|
|
|
|
pub async fn register(
|
|
(cookies, authenticated, state, session, form): RegisterArgs,
|
|
) -> Result<Result<RegisterState, HttpResponse>, Error> {
|
|
if cookies.is_none() {
|
|
return Ok(Err(to_cookie_page(&state)));
|
|
}
|
|
|
|
if authenticated.is_some() {
|
|
return Ok(Err(to_home(&state)));
|
|
}
|
|
|
|
let form = form.into_inner();
|
|
|
|
match try_register(session, &form, &state).await? {
|
|
Ok(res) => Ok(Err(res)),
|
|
Err(e) => Ok(Ok(RegisterState::new_from_request(&state, form, e))),
|
|
}
|
|
}
|
|
|
|
impl RegisterState {
|
|
fn new_empty(state: &State) -> Self {
|
|
RegisterState {
|
|
state: state.clone(),
|
|
form: None,
|
|
error: None,
|
|
dark: false,
|
|
}
|
|
}
|
|
|
|
fn new_from_request(state: &State, form: RegisterForm, error: RegisterError) -> Self {
|
|
RegisterState {
|
|
state: state.clone(),
|
|
form: Some(form),
|
|
error: Some(error),
|
|
dark: false,
|
|
}
|
|
}
|
|
|
|
pub fn dark(&mut self, dark: bool) {
|
|
self.dark = dark;
|
|
}
|
|
|
|
pub(crate) fn register_path(&self) -> String {
|
|
self.state.pages.register_path()
|
|
}
|
|
|
|
pub(crate) fn login_path(&self) -> String {
|
|
self.state.pages.login_path()
|
|
}
|
|
|
|
pub(crate) fn home_path(&self) -> String {
|
|
self.state.pages.home_path()
|
|
}
|
|
|
|
pub(crate) fn username(&self) -> Option<String> {
|
|
self.form.as_ref().map(|form| form.username.clone())
|
|
}
|
|
|
|
pub(crate) fn username_error(&self) -> Option<String> {
|
|
self.error.as_ref().and_then(|e| e.username())
|
|
}
|
|
|
|
pub(crate) fn password(&self) -> Option<String> {
|
|
self.form.as_ref().map(|form| form.password.clone())
|
|
}
|
|
|
|
pub(crate) fn confirmation(&self) -> Option<String> {
|
|
self.form
|
|
.as_ref()
|
|
.map(|form| form.password_confirmation.clone())
|
|
}
|
|
|
|
pub(crate) fn confirmation_error(&self) -> Option<String> {
|
|
self.error.as_ref().and_then(|e| e.confirmation())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum RegisterError {
|
|
UsernameTaken,
|
|
PasswordMatch,
|
|
}
|
|
|
|
impl RegisterError {
|
|
fn username(&self) -> Option<String> {
|
|
match self {
|
|
RegisterError::UsernameTaken => Some("Username is already taken".to_owned()),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn confirmation(&self) -> Option<String> {
|
|
match self {
|
|
RegisterError::PasswordMatch => Some("Passwords do not match".to_owned()),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn try_register(
|
|
session: Session,
|
|
form: &RegisterForm,
|
|
state: &State,
|
|
) -> Result<Result<HttpResponse, RegisterError>, Error> {
|
|
if form.password != form.password_confirmation {
|
|
return Ok(Err(RegisterError::PasswordMatch));
|
|
}
|
|
|
|
let res = state
|
|
.user_store
|
|
.exec(crate::store::Register {
|
|
username: form.username.clone(),
|
|
password: form.password.clone(),
|
|
})
|
|
.await;
|
|
|
|
let user = match res {
|
|
Ok(user) => user,
|
|
Err(BlockingError::Error(crate::store::StoreError::InUse)) => {
|
|
return Ok(Err(RegisterError::UsernameTaken))
|
|
}
|
|
Err(e) => return Err(e.into()),
|
|
};
|
|
|
|
crate::extractors::UserData::set_data(user.id(), &session)?;
|
|
|
|
Ok(Ok(to_home(state)))
|
|
}
|