feat: bootstrap identity web adapter
This commit is contained in:
parent
2a85f88e04
commit
41c4657741
5 changed files with 250 additions and 3 deletions
|
@ -1,3 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
pub mod web;
|
||||
|
|
134
src/identity/adapters/input/web/errors.rs
Normal file
134
src/identity/adapters/input/web/errors.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{HttpResponse, ResponseError};
|
||||
use derive_more::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::identity::application::services::errors::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
struct ErrorResponse {
|
||||
error: String,
|
||||
}
|
||||
|
||||
impl From<WebError> for ErrorResponse {
|
||||
fn from(value: WebError) -> Self {
|
||||
ErrorResponse {
|
||||
error: serde_json::to_string(&value).unwrap_or_else(|_| {
|
||||
log::error!("Unable to serialize error");
|
||||
"Unable to serialize error".into()
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum WebError {
|
||||
InternalError,
|
||||
BadRequest,
|
||||
|
||||
DuplicateUsername,
|
||||
VerificationOTPNotFound,
|
||||
VerificationSecretNotFound,
|
||||
PhoneNumberVerificationFailed,
|
||||
LoginOTPNotFound,
|
||||
LoginFailed,
|
||||
DuplicateEmail,
|
||||
DuplicateEmployeeID,
|
||||
DuplicatePhoneNumber,
|
||||
DuplicateVerificationOTP,
|
||||
PhoneNumberNotFound,
|
||||
EmployeeNotFound,
|
||||
InviteNotFound,
|
||||
StoreNotFound,
|
||||
DuplicateStoreName,
|
||||
StoreIDNotFound,
|
||||
DuplicateStoreID,
|
||||
}
|
||||
|
||||
impl From<IdentityError> for WebError {
|
||||
fn from(v: IdentityError) -> Self {
|
||||
match v {
|
||||
IdentityError::InternalError => Self::InternalError,
|
||||
IdentityError::StoreIDNotFound => Self::StoreNotFound,
|
||||
IdentityError::DuplicateUsername => Self::DuplicateUsername,
|
||||
IdentityError::VerificationOTPNotFound => Self::VerificationOTPNotFound,
|
||||
IdentityError::VerificationSecretNotFound => Self::VerificationSecretNotFound,
|
||||
IdentityError::PhoneNumberVerificationFailed => Self::PhoneNumberNotFound,
|
||||
IdentityError::LoginOTPNotFound => Self::LoginOTPNotFound,
|
||||
IdentityError::LoginFailed => Self::LoginFailed,
|
||||
IdentityError::DuplicateEmail => Self::DuplicateEmail,
|
||||
IdentityError::DuplicateEmployeeID => Self::DuplicateEmployeeID,
|
||||
IdentityError::DuplicatePhoneNumber => Self::DuplicatePhoneNumber,
|
||||
IdentityError::DuplicateVerificationOTP => Self::DuplicateVerificationOTP,
|
||||
IdentityError::PhoneNumberNotFound => Self::PhoneNumberNotFound,
|
||||
IdentityError::EmployeeNotFound => Self::EmployeeNotFound,
|
||||
IdentityError::InviteNotFound => Self::InviteNotFound,
|
||||
IdentityError::StoreNotFound => Self::StoreNotFound,
|
||||
IdentityError::DuplicateStoreName => Self::DuplicateStoreName,
|
||||
IdentityError::StoreIDNotFound => Self::StoreIDNotFound,
|
||||
IdentityError::DuplicateStoreID => Self::DuplicateStoreID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for WebError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
Self::InternalError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Self::BadRequest => StatusCode::BAD_REQUEST,
|
||||
|
||||
Self::StoreIDNotFound => StatusCode::NOT_FOUND,
|
||||
Self::DuplicateUsername => StatusCode::BAD_REQUEST,
|
||||
Self::VerificationOTPNotFound => StatusCode::UNAUTHORIZED,
|
||||
Self::VerificationSecretNotFound => StatusCode::UNAUTHORIZED,
|
||||
Self::PhoneNumberVerificationFailed => StatusCode::UNAUTHORIZED,
|
||||
Self::LoginOTPNotFound => StatusCode::UNAUTHORIZED,
|
||||
Self::LoginFailed => StatusCode::UNAUTHORIZED,
|
||||
Self::DuplicateEmail => StatusCode::BAD_REQUEST,
|
||||
Self::DuplicateEmployeeID => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Self::DuplicatePhoneNumber => StatusCode::BAD_REQUEST,
|
||||
Self::DuplicateVerificationOTP => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Self::PhoneNumberNotFound => StatusCode::UNAUTHORIZED, // (?)
|
||||
Self::EmployeeNotFound => StatusCode::NOT_FOUND,
|
||||
Self::InviteNotFound => StatusCode::NOT_FOUND,
|
||||
Self::StoreNotFound => StatusCode::NOT_FOUND,
|
||||
Self::DuplicateStoreName => StatusCode::BAD_REQUEST,
|
||||
Self::StoreIDNotFound => StatusCode::NOT_FOUND,
|
||||
Self::DuplicateStoreID => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> actix_web::HttpResponse {
|
||||
let e: ErrorResponse = self.clone().into();
|
||||
match self {
|
||||
Self::InternalError => HttpResponse::InternalServerError().json(e),
|
||||
Self::BadRequest => HttpResponse::BadRequest().json(e),
|
||||
|
||||
Self::StoreNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::StoreIDNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::DuplicateUsername => HttpResponse::BadRequest().json(e),
|
||||
Self::VerificationOTPNotFound => HttpResponse::Unauthorized().json(e),
|
||||
Self::VerificationSecretNotFound => HttpResponse::Unauthorized().json(e),
|
||||
Self::PhoneNumberVerificationFailed => HttpResponse::Unauthorized().json(e),
|
||||
Self::LoginOTPNotFound => HttpResponse::Unauthorized().json(e),
|
||||
Self::LoginFailed => HttpResponse::Unauthorized().json(e),
|
||||
Self::DuplicateEmail => HttpResponse::BadRequest().json(e),
|
||||
Self::DuplicateEmployeeID => HttpResponse::InternalServerError().json(e),
|
||||
Self::DuplicatePhoneNumber => HttpResponse::BadRequest().json(e),
|
||||
Self::DuplicateVerificationOTP => HttpResponse::InternalServerError().json(e),
|
||||
Self::PhoneNumberNotFound => HttpResponse::Unauthorized().json(e), // (?)
|
||||
Self::EmployeeNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::InviteNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::StoreNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::DuplicateStoreName => HttpResponse::BadRequest().json(e),
|
||||
Self::StoreIDNotFound => HttpResponse::NotFound().json(e),
|
||||
Self::DuplicateStoreID => HttpResponse::InternalServerError().json(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type WebJsonRepsonse<V> = Result<V, WebError>;
|
28
src/identity/adapters/input/web/mod.rs
Normal file
28
src/identity/adapters/input/web/mod.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web;
|
||||
|
||||
use crate::identity::adapters::types;
|
||||
|
||||
mod errors;
|
||||
mod owner;
|
||||
mod routes;
|
||||
|
||||
pub use errors::WebJsonRepsonse;
|
||||
|
||||
pub use routes::RoutesRepository;
|
||||
|
||||
pub fn load_ctx() -> impl FnOnce(&mut web::ServiceConfig) {
|
||||
let routes = types::WebIdentityRoutesRepository::new(Arc::new(RoutesRepository::default()));
|
||||
|
||||
let f = move |cfg: &mut web::ServiceConfig| {
|
||||
cfg.app_data(routes);
|
||||
cfg.configure(owner::services);
|
||||
};
|
||||
|
||||
Box::new(f)
|
||||
}
|
86
src/identity/adapters/input/web/routes.rs
Normal file
86
src/identity/adapters/input/web/routes.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct RoutesRepository {
|
||||
owner_login: String,
|
||||
owner_register: String,
|
||||
owner_delete: String,
|
||||
owner_verify_email: String,
|
||||
owner_resend_verification_email: String,
|
||||
// owner_set_admin: String,
|
||||
owner_update_email: String,
|
||||
owner_change_password: String,
|
||||
|
||||
owner_add_store: String,
|
||||
owner_update_store: String,
|
||||
|
||||
employee_exit_organization: String,
|
||||
employee_login: String,
|
||||
employee_register: String,
|
||||
employee_resend_login_otp: String,
|
||||
employee_resend_verification_otp: String,
|
||||
employee_verify_phone_number: String,
|
||||
}
|
||||
|
||||
impl Default for RoutesRepository {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
owner_login: "/owner/login".into(),
|
||||
owner_register: "/owner/register".into(),
|
||||
owner_delete: "/owner/user/delete".into(),
|
||||
owner_verify_email: "/owner/user/verify/email".into(),
|
||||
owner_resend_verification_email: "/owner/user/verify/email/resend".into(),
|
||||
owner_update_email: "/owner/user/email/update".into(),
|
||||
owner_change_password: "/owner/password/change".into(),
|
||||
//owner_set_admin: "/owner/user/promote/admin".into(),
|
||||
owner_add_store: "/owner/store".into(),
|
||||
owner_update_store: "/owner/store/update".into(),
|
||||
|
||||
employee_login: "/employee/login".into(),
|
||||
employee_register: "/employee/register".into(),
|
||||
employee_resend_login_otp: "/employee/login/resend_otp".into(),
|
||||
employee_resend_verification_otp: "/employee/user/phone/verify/resend_otp".into(),
|
||||
employee_verify_phone_number: "/employee/user/phone/verify".into(),
|
||||
employee_exit_organization: "/employee/organization/exit".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RoutesRepository {
|
||||
// pub fn update_bill(&self, bill_id: Uuid) -> String {
|
||||
// self.update_bill
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// }
|
||||
|
||||
// pub fn delete_bill(&self, bill_id: Uuid) -> String {
|
||||
// self.delete_bill
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// }
|
||||
|
||||
// pub fn compute_total_price_for_bill(&self, bill_id: Uuid) -> String {
|
||||
// self.compute_total_price_for_bill
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// }
|
||||
|
||||
// pub fn add_line_item(&self, bill_id: Uuid) -> String {
|
||||
// self.add_line_item
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// }
|
||||
|
||||
// pub fn update_line_item(&self, bill_id: Uuid, line_item_uuid: Uuid) -> String {
|
||||
// self.update_line_item
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// .replace("{line_item_uuid}", &line_item_uuid.to_string())
|
||||
// }
|
||||
|
||||
// pub fn delete_line_item(&self, bill_id: Uuid, line_item_uuid: Uuid) -> String {
|
||||
// self.delete_line_item
|
||||
// .replace("{bill_uuid}", &bill_id.to_string())
|
||||
// .replace("{line_item_uuid}", &line_item_uuid.to_string())
|
||||
// }
|
||||
}
|
|
@ -10,9 +10,7 @@ use postgres_es::PostgresCqrs;
|
|||
use sqlx::postgres::PgPool;
|
||||
|
||||
use crate::identity::{
|
||||
application::{
|
||||
services::{IdentityServices, IdentityServicesObj},
|
||||
},
|
||||
application::services::{IdentityServices, IdentityServicesObj},
|
||||
domain::{aggregate::User, employee_aggregate::Employee, store_aggregate::Store},
|
||||
};
|
||||
use crate::settings::Settings;
|
||||
|
|
Loading…
Reference in a new issue