use actix::Addr; use actix_session::Session; use actix_web::web::{Data, Json, ServiceConfig}; use actix_web::{delete, get, post, HttpResponse}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use crate::database::Database; use crate::logic::hash_pass; use crate::model::{Account, Email, Login, PassHash, Password, PasswordConfirmation, Role}; use crate::routes::{RequireLogin, Result}; use crate::{database, routes, Config}; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Can't register new account")] Register, #[error("Can't hash password")] HashPass, #[error("Internal server error")] DatabaseConnection, #[error("{0}")] Database(#[from] database::Error), } #[derive(Serialize)] pub struct LogoutResponse {} #[delete("/admin/logout")] async fn logout(session: Session) -> Result { session.require_admin()?; Ok(HttpResponse::NotImplemented().body("")) } #[post("/admin/sign-in")] async fn sign_in(_session: Session) -> Result { Ok(HttpResponse::NotImplemented().body("")) } #[derive(Deserialize)] pub struct RegisterInput { pub login: Login, pub email: Email, pub password: Password, pub password_confirmation: PasswordConfirmation, pub role: Role, } #[derive(Serialize, Default)] pub struct RegisterResponse { pub success: bool, pub errors: Vec, pub account: Option, } #[derive(Serialize)] pub enum RegisterError { PasswordDiffer, } // login_required #[post("/admin/register")] async fn register( session: Session, Json(input): Json, db: Data>, config: Data>, ) -> Result { let mut response = RegisterResponse::default(); session.require_admin()?; if input.password != input.password_confirmation { response.errors.push(RegisterError::PasswordDiffer); } let hash = match hash_pass(&input.password.0, &config.pass_salt) { Ok(s) => s, Err(e) => { log::error!("{e:?}"); return Err(routes::Error::Admin(Error::HashPass)); } }; match db .send(database::CreateAccount { email: input.email, login: input.login, pass_hash: PassHash(hash), role: input.role, }) .await { Ok(Ok(account)) => { response.account = Some(account.into()); } Ok(Err(e)) => { log::error!("{}", e); return Err(super::Error::Admin(Error::Register)); } Err(e) => { log::error!("{}", e); return Err(super::Error::Admin(Error::Register)); } }; response.success = response.errors.is_empty(); Ok(if response.success { HttpResponse::NotImplemented().json(response) } else { HttpResponse::BadRequest().json(response) }) } #[get("/admin/api/v1/products")] async fn api_v1_products(session: Session, db: Data>) -> Result { session.require_admin()?; match db.send(database::AllProducts).await { Ok(Ok(products)) => Ok(HttpResponse::Ok().json(products)), Ok(Err(e)) => { log::error!("{}", e); Err(super::Error::Admin(Error::Database(e))) } Err(e) => { log::error!("{}", e); Err(super::Error::Admin(Error::DatabaseConnection)) } } } #[get("/admin")] async fn landing() -> Result { Ok(HttpResponse::NotImplemented().body("")) } pub fn configure(config: &mut ServiceConfig) { config.service(landing).service(sign_in).service(logout).service(register); }