diff --git a/imphnen-backend/src/bin/seed_permissions.rs b/imphnen-backend/src/bin/seed_permissions.rs index 3f878d8..e412651 100644 --- a/imphnen-backend/src/bin/seed_permissions.rs +++ b/imphnen-backend/src/bin/seed_permissions.rs @@ -25,8 +25,8 @@ async fn main() -> Result<(), Box> { ( "0269ed71-0ae0-4c43-ad29-e3d861d8f9a0", "Create Permissions", - None, - None, + Some("2025-01-29T05:11:01.265+00"), + Some("2025-01-29T05:11:01.265001+00"), ), ( "299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b", @@ -37,20 +37,20 @@ async fn main() -> Result<(), Box> { ( "319ee593-ff0a-4f29-bbaf-9feb3174a3a2", "Create Roles", - None, - None, + Some("2025-01-29T05:11:01.265+00"), + Some("2025-01-29T05:11:01.265001+00"), ), ( "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", "Read Detail Users", - None, - None, + Some("2025-01-29T05:11:01.265+00"), + Some("2025-01-29T05:11:01.265001+00"), ), ( "35b0d992-65c8-4b62-b030-e6e0320e4048", "Delete Roles", - None, - None, + Some("2025-01-29T05:34:40.621554+00"), + Some("2025-01-29T05:34:40.621555+00"), ), ( "4da8b434-89f9-4d91-85ae-eebd63cdbeda", @@ -91,8 +91,8 @@ async fn main() -> Result<(), Box> { ( "9164ca6e-c7e3-4238-a15f-f36ab9577e7e", "Read List Roles", - None, - None, + Some("2025-01-29T05:34:40.621554+00"), + Some("2025-01-29T05:34:40.621555+00"), ), ( "96df0689-2ae9-4894-bf00-837c19415e5c", @@ -109,8 +109,8 @@ async fn main() -> Result<(), Box> { ( "a00d5608-4c48-4542-845c-dfe004687022", "Update Roles", - None, - None, + Some("2025-01-29T05:34:40.621554+00"), + Some("2025-01-29T05:34:40.621555+00"), ), ( "b2dc3928-86ba-4c59-a03d-0b57d5183ebc", diff --git a/imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs b/imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs index 5c608cb..436a899 100644 --- a/imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs +++ b/imphnen-gacha/src/v1/gacha_item/gacha_item_repository.rs @@ -28,6 +28,8 @@ impl<'a> GachaItemRepository<'a> { &meta, conditions, None, + "name", + None, ) .await } diff --git a/imphnen-gateway/src/docs.rs b/imphnen-gateway/src/docs.rs index 9f9ab3f..61751fe 100644 --- a/imphnen-gateway/src/docs.rs +++ b/imphnen-gateway/src/docs.rs @@ -1,6 +1,5 @@ use imphnen_iam::{ -auth, permissions, roles, users, AuthLoginRequestDto, AuthLoginResponsetDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, - AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsItemDto, PermissionsRequestDto, ResponseListSuccessDto, ResponseSuccessDto, RolesItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto, UsersItemDto, UsersListItemDto, UsersUpdateRequestDto +auth, permissions, roles, users, AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsItemDto, PermissionsRequestDto, ResponseListSuccessDto, ResponseSuccessDto, RolesDetailItemDto, RolesListItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto, UsersListItemDto, UsersUpdateRequestDto }; use utoipa::{ openapi::security::{Http, HttpAuthScheme, SecurityScheme}, @@ -48,18 +47,18 @@ use utoipa::{ AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, ResponseSuccessDto, - RolesItemDto, + RolesListItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, PermissionsRequestDto, PermissionsItemDto, - UsersItemDto, + UsersDetailItemDto, UsersListItemDto, UsersUpdateRequestDto, UsersCreateRequestDto, ResponseSuccessDto, - ResponseListSuccessDto>, - ResponseSuccessDto, + ResponseListSuccessDto>, + ResponseSuccessDto, ResponseListSuccessDto>, ResponseSuccessDto, ResponseListSuccessDto>, diff --git a/imphnen-iam/src/v1/auth/auth_dto.rs b/imphnen-iam/src/v1/auth/auth_dto.rs index 90374c4..d4f0883 100644 --- a/imphnen-iam/src/v1/auth/auth_dto.rs +++ b/imphnen-iam/src/v1/auth/auth_dto.rs @@ -1,25 +1,29 @@ -use crate::RolesItemDto; use lazy_static::lazy_static; use regex::Regex; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use validator::{Validate, ValidationError}; +use crate::UsersDetailItemDto; + lazy_static! { - static ref PASSWORD_REGEX: Regex = Regex::new(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$").unwrap(); + static ref PASSWORD_REGEX: Regex = Regex::new( + r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$" + ) + .unwrap(); } fn validate_password_complexity(password: &str) -> Result<(), ValidationError> { - let has_uppercase = password.chars().any(|c| c.is_ascii_uppercase()); - let has_lowercase = password.chars().any(|c| c.is_ascii_lowercase()); - let has_digit = password.chars().any(|c| c.is_ascii_digit()); - let has_special = password.chars().any(|c| "@$!%*?&".contains(c)); + let has_uppercase = password.chars().any(|c| c.is_ascii_uppercase()); + let has_lowercase = password.chars().any(|c| c.is_ascii_lowercase()); + let has_digit = password.chars().any(|c| c.is_ascii_digit()); + let has_special = password.chars().any(|c| "@$!%*?&".contains(c)); - if has_uppercase && has_lowercase && has_digit && has_special { - Ok(()) - } else { - Err(ValidationError::new("complexity")) - } + if has_uppercase && has_lowercase && has_digit && has_special { + Ok(()) + } else { + Err(ValidationError::new("complexity")) + } } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] @@ -33,23 +37,10 @@ pub struct AuthLoginRequestDto { pub password: String, } -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] -pub struct AuthUserItemDto { - pub id: String, - pub role: RolesItemDto, - pub fullname: String, - pub email: String, - pub avatar: Option, - pub phone_number: String, - pub is_active: bool, - pub gender: Option, - pub birthdate: Option, -} - #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] pub struct AuthLoginResponsetDto { pub token: TokenDto, - pub user: AuthUserItemDto, + pub user: UsersDetailItemDto, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema)] @@ -77,28 +68,7 @@ pub struct AuthRegisterRequestDto { #[validate(length(min = 2, message = "Fullname at least have 2 character"))] pub fullname: String, #[validate(length(min = 1, message = "Student type is required"))] - pub student_type: String, - #[validate(length( - min = 10, - message = "Phone number at least have 10 character" - ))] pub phone_number: String, - #[validate(length( - max = 4, - message = "Referal code cannot be more than 4 character" - ))] - pub referral_code: Option, - pub referred_by: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] -pub struct AuthActiveInactiveRequestDto { - pub is_active: bool, - #[validate( - length(min = 1, message = "Email cannot be empty"), - email(message = "Email not valid") - )] - pub email: String, } #[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)] diff --git a/imphnen-iam/src/v1/auth/auth_repository.rs b/imphnen-iam/src/v1/auth/auth_repository.rs index 7fa4076..9b44161 100644 --- a/imphnen-iam/src/v1/auth/auth_repository.rs +++ b/imphnen-iam/src/v1/auth/auth_repository.rs @@ -1,6 +1,6 @@ use super::AuthOtpSchema; -use crate::{make_thing, AppState, ResourceEnum, UsersItemDtoRaw}; -use anyhow::{anyhow, bail, Result}; +use crate::{AppState, ResourceEnum, UsersDetailQueryDto, make_thing}; +use anyhow::{Result, anyhow, bail}; use chrono::{Duration, Utc}; pub struct AuthRepository<'a> { @@ -12,7 +12,7 @@ impl<'a> AuthRepository<'a> { Self { state } } - pub async fn query_store_user(&self, user: UsersItemDtoRaw) -> Result { + pub async fn query_store_user(&self, user: UsersDetailQueryDto) -> Result { if user.email.trim().is_empty() { bail!("Email is required"); } @@ -22,11 +22,11 @@ impl<'a> AuthRepository<'a> { let _ = self .state .surrealdb_mem - .delete::>((table.clone(), user_id.clone())) + .delete::>((table.clone(), user_id.clone())) .await?; let mut user_to_store = user.clone(); user_to_store.id = id.clone(); - let record: Option = self + let record: Option = self .state .surrealdb_mem .create((table, user_id)) @@ -41,8 +41,8 @@ impl<'a> AuthRepository<'a> { pub async fn query_get_stored_user( &self, email: String, - ) -> Result { - let user: Option = self + ) -> Result { + let user: Option = self .state .surrealdb_mem .select((ResourceEnum::UsersCache.to_string(), email)) @@ -54,7 +54,7 @@ impl<'a> AuthRepository<'a> { } pub async fn query_delete_stored_user(&self, email: String) -> Result { - let record: Option = self + let record: Option = self .state .surrealdb_mem .delete((ResourceEnum::UsersCache.to_string(), email)) diff --git a/imphnen-iam/src/v1/auth/auth_service.rs b/imphnen-iam/src/v1/auth/auth_service.rs index 76df782..c59e0a0 100644 --- a/imphnen-iam/src/v1/auth/auth_service.rs +++ b/imphnen-iam/src/v1/auth/auth_service.rs @@ -1,15 +1,15 @@ use super::{ AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthRegisterRequestDto, AuthRepository, - AuthResendOtpRequestDto, AuthUserItemDto, AuthVerifyEmailRequestDto, TokenDto, + AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, TokenDto, }; use crate::{ - common_response, decode_refresh_token, encode_access_token, encode_refresh_token, + AppState, Env, ResourceEnum, ResponseSuccessDto, RolesEnum, RolesRepository, + UsersDetailItemDto, UsersRepository, UsersSchema, common_response, + decode_refresh_token, encode_access_token, encode_refresh_token, encode_reset_password_token, extract_email_token, generate_otp, get_iso_date, hash_password, make_thing, send_email, success_response, validate_request, - verify_password, AppState, Env, ResourceEnum, ResponseSuccessDto, RolesEnum, - RolesItemDto, RolesRepository, UsersActiveInactiveSchema, UsersRepository, - UsersSchema, UsersSetNewPasswordSchema, + verify_password, }; use axum::{http::StatusCode, response::Response}; use surrealdb::Uuid; @@ -27,7 +27,6 @@ impl AuthService { let user_repo = UsersRepository::new(state); let auth_repo = AuthRepository::new(state); - let role_repo = RolesRepository::new(state); match user_repo.query_user_by_email(payload.email.clone()).await { Ok(user) => { @@ -54,7 +53,7 @@ impl AuthService { return common_response( StatusCode::INTERNAL_SERVER_ERROR, "Failed to generate access token", - ) + ); } }; @@ -64,34 +63,13 @@ impl AuthService { return common_response( StatusCode::INTERNAL_SERVER_ERROR, "Failed to generate refresh token", - ) + ); } }; - let role_response = role_repo - .query_role_by_id(user.role.id.id.to_raw()) - .await - .unwrap(); - let response = ResponseSuccessDto { data: AuthLoginResponsetDto { - user: AuthUserItemDto { - id: user.id.id.to_raw(), - fullname: user.fullname.clone(), - email: user.email.clone(), - is_active: user.is_active.clone(), - avatar: user.avatar.clone(), - phone_number: user.phone_number.clone(), - gender: user.gender.clone(), - birthdate: user.birthdate.clone(), - role: RolesItemDto { - id: role_response.id, - name: role_response.name, - permissions: role_response.permissions, - created_at: role_response.created_at, - updated_at: role_response.updated_at, - }, - }, + user: UsersDetailItemDto::from(&user), token: TokenDto { access_token, refresh_token, @@ -116,6 +94,7 @@ impl AuthService { if let Err((status, message)) = validate_request(&payload) { return common_response(status, &message); } + let user_repo = UsersRepository::new(state); let auth_repo = AuthRepository::new(state); let role_repo = RolesRepository::new(state); @@ -126,6 +105,7 @@ impl AuthService { Ok(role) => role, Err(_) => return common_response(StatusCode::BAD_REQUEST, "Role Not Found"), }; + if user_repo .query_user_by_email(payload.email.clone()) .await @@ -133,6 +113,7 @@ impl AuthService { { return common_response(StatusCode::BAD_REQUEST, "User already exists"); } + let hashed_password = match hash_password(&payload.password) { Ok(hash) => hash, Err(_) => { @@ -142,16 +123,16 @@ impl AuthService { ); } }; + let new_user = AuthRegisterRequestDto { email: payload.email, password: hashed_password, fullname: payload.fullname, - student_type: payload.student_type, phone_number: payload.phone_number, - referral_code: payload.referral_code, - referred_by: payload.referred_by, }; + let otp = generate_otp::OtpManager::generate_otp(); + match auth_repo .query_store_otp(new_user.email.clone(), otp.clone()) .await @@ -169,11 +150,13 @@ impl AuthService { return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()); } } + let role_thing = make_thing(&ResourceEnum::Roles.to_string(), &role.id); let user_thing = make_thing( &ResourceEnum::Users.to_string(), &Uuid::new_v4().to_string(), ); + match user_repo .query_create_user(UsersSchema { id: user_thing, @@ -202,14 +185,18 @@ impl AuthService { if let Err((status, message)) = validate_request(&payload) { return common_response(status, &message); } - + let user_repo = UsersRepository::new(state); - if user_repo.query_user_by_email(payload.email.clone()).await.is_err() { + if user_repo + .query_user_by_email(payload.email.clone()) + .await + .is_err() + { return common_response(StatusCode::BAD_REQUEST, "User not found"); } let auth_repo = AuthRepository::new(state); - let _ = auth_repo.query_get_stored_otp(payload.email.clone()).await; + let _ = auth_repo.query_get_stored_otp(payload.email.clone()).await; let otp = generate_otp::OtpManager::generate_otp(); let message = format!("Your OTP code is {}", otp); @@ -273,10 +260,10 @@ impl AuthService { let user = match user_result { Ok(user) => user, Err(err) if err.to_string().contains("User not found") => { - return common_response(StatusCode::BAD_REQUEST, "User not found") + return common_response(StatusCode::BAD_REQUEST, "User not found"); } Err(err) => { - return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()) + return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()); } }; let token = match encode_reset_password_token(user.email) { @@ -285,7 +272,7 @@ impl AuthService { return common_response( StatusCode::INTERNAL_SERVER_ERROR, "Failed to generate access token", - ) + ); } }; let env = Env::new(); @@ -310,15 +297,18 @@ impl AuthService { let user_repo = UsersRepository::new(state); let auth_repo = AuthRepository::new(state); let email = payload.email.clone(); + let user = match user_repo.query_user_by_email(email.clone()).await { + Ok(user) if !user.is_deleted => user, + _ => return common_response(StatusCode::NOT_FOUND, "User not found"), + }; + let patch = UsersSchema { + id: user.id.clone(), + is_active: true, + ..UsersSchema::from(user) + }; match auth_repo.query_get_stored_otp(email.clone()).await { Ok(stored_otp) => match stored_otp == payload.otp { - true => match user_repo - .query_active_inactive_user( - email.clone(), - UsersActiveInactiveSchema { is_active: true }, - ) - .await - { + true => match user_repo.query_update_user(patch).await { Ok(_) => match auth_repo.query_delete_stored_otp(email).await { Ok(_) => common_response(StatusCode::OK, "Email verified successfully"), Err(e) => { @@ -346,7 +336,7 @@ impl AuthService { if let Err((status, message)) = validate_request(&payload) { return common_response(status, &message); } - let user_repo = UsersRepository::new(state); + let repo = UsersRepository::new(state); let email = match extract_email_token(payload.token.clone()) { Some(email) => email, None => { @@ -362,12 +352,18 @@ impl AuthService { ); } }; - match user_repo - .query_update_password_user(email, UsersSetNewPasswordSchema { password }) - .await - { + let user = match repo.query_user_by_email(email.clone()).await { + Ok(user) if !user.is_deleted => user, + _ => return common_response(StatusCode::NOT_FOUND, "User not found"), + }; + let patch = UsersSchema { + id: user.id.clone(), + password, + ..Default::default() + }; + match repo.query_update_user(patch).await { Ok(msg) => common_response(StatusCode::OK, &msg), - Err(err) => common_response(StatusCode::BAD_REQUEST, &err.to_string()), + Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()), } } } diff --git a/imphnen-iam/src/v1/permissions/permissions_repository.rs b/imphnen-iam/src/v1/permissions/permissions_repository.rs index ce3e8f4..1d1b0cf 100644 --- a/imphnen-iam/src/v1/permissions/permissions_repository.rs +++ b/imphnen-iam/src/v1/permissions/permissions_repository.rs @@ -1,9 +1,9 @@ -use super::{PermissionsItemDto, PermissionsItemDtoRaw, PermissionsSchema}; +use super::{PermissionsItemDto, PermissionsSchema}; use crate::{ - get_id, make_thing, query_list_with_meta, AppState, MetaRequestDto, ResourceEnum, - ResponseListSuccessDto, + AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto, get_id, + make_thing, query_list_with_meta, }; -use anyhow::{bail, Result}; +use anyhow::{Result, bail}; use imphnen_utils::extract_id; pub struct PermissionsRepository<'a> { @@ -27,14 +27,17 @@ impl<'a> PermissionsRepository<'a> { let filter_by = meta.filter_by.as_ref().unwrap(); conditions.push(format!("{} = $filter", filter_by)); } - let raw_result: ResponseListSuccessDto> = query_list_with_meta( - &self.state.surrealdb_ws, - &ResourceEnum::Permissions.to_string(), - &meta, - conditions, - None, - ) - .await?; + let raw_result: ResponseListSuccessDto> = + query_list_with_meta( + &self.state.surrealdb_ws, + &ResourceEnum::Permissions.to_string(), + &meta, + conditions, + None, + "name", + None, + ) + .await?; let transformed_data = raw_result .data .into_iter() @@ -69,9 +72,7 @@ impl<'a> PermissionsRepository<'a> { &self, id: String, ) -> Result { - let raw_result = self - .query_permission_by_id(id.clone()) - .await?; + let raw_result = self.query_permission_by_id(id.clone()).await?; let transformed_data = PermissionsItemDto { id: extract_id(&raw_result.id), name: raw_result.name, @@ -81,7 +82,6 @@ impl<'a> PermissionsRepository<'a> { Ok(transformed_data) } - pub async fn query_permission_by_name( &self, name: String, diff --git a/imphnen-iam/src/v1/permissions/permissions_schema.rs b/imphnen-iam/src/v1/permissions/permissions_schema.rs index ba08b3a..274743a 100644 --- a/imphnen-iam/src/v1/permissions/permissions_schema.rs +++ b/imphnen-iam/src/v1/permissions/permissions_schema.rs @@ -1,6 +1,6 @@ -use crate::{make_thing, ResourceEnum}; +use crate::{ResourceEnum, make_thing}; use serde::{Deserialize, Serialize}; -use surrealdb::{sql::Thing, Uuid}; +use surrealdb::{Uuid, sql::Thing}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PermissionsSchema { diff --git a/imphnen-iam/src/v1/users/users_dto.rs b/imphnen-iam/src/v1/users/users_dto.rs index 41c29f6..4e3d8b0 100644 --- a/imphnen-iam/src/v1/users/users_dto.rs +++ b/imphnen-iam/src/v1/users/users_dto.rs @@ -95,19 +95,19 @@ pub struct UsersDetailItemDto { } impl UsersDetailItemDto { - pub fn from(dto: UsersDetailQueryDto) -> Self { + pub fn from(dto: &UsersDetailQueryDto) -> Self { Self { - id: dto.id.id.to_raw(), + id: dto.id.id.to_raw().clone(), role: RolesDetailItemDto::from(&dto.role), - fullname: dto.fullname, - email: dto.email, - avatar: dto.avatar, - phone_number: dto.phone_number, - is_active: dto.is_active, - gender: dto.gender, - birthdate: dto.birthdate, - created_at: dto.created_at, - updated_at: dto.updated_at, + fullname: dto.fullname.clone(), + email: dto.email.clone(), + avatar: dto.avatar.clone(), + phone_number: dto.phone_number.clone(), + is_active: dto.is_active.clone(), + gender: dto.gender.clone(), + birthdate: dto.birthdate.clone(), + created_at: dto.created_at.clone(), + updated_at: dto.updated_at.clone(), } } } diff --git a/imphnen-iam/src/v1/users/users_service.rs b/imphnen-iam/src/v1/users/users_service.rs index f4f41f9..b401fc6 100644 --- a/imphnen-iam/src/v1/users/users_service.rs +++ b/imphnen-iam/src/v1/users/users_service.rs @@ -34,7 +34,7 @@ impl UsersService { let repo = UsersRepository::new(state); match repo.query_user_by_id(id).await { Ok(user) if !user.is_deleted => success_response(ResponseSuccessDto { - data: UsersDetailItemDto::from(user), + data: UsersDetailItemDto::from(&user), }), Ok(_) => common_response(StatusCode::NOT_FOUND, "User not found"), Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()), @@ -49,7 +49,7 @@ impl UsersService { }; match repo.query_user_by_email(email).await { Ok(user) if !user.is_deleted => success_response(ResponseSuccessDto { - data: UsersDetailItemDto::from(user), + data: UsersDetailItemDto::from(&user), }), Ok(_) => common_response(StatusCode::NOT_FOUND, "User not found"), Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()), diff --git a/imphnen-middleware/src/auth_middleware/mod.rs b/imphnen-middleware/src/auth_middleware/mod.rs index d91068b..f5c4f07 100644 --- a/imphnen-middleware/src/auth_middleware/mod.rs +++ b/imphnen-middleware/src/auth_middleware/mod.rs @@ -2,7 +2,7 @@ use axum::{ Extension, extract::Request, http::StatusCode, middleware::Next, response::Response, }; -use imphnen_iam::{UsersItemDtoRaw, UsersRepository}; +use imphnen_iam::{UsersDetailQueryDto, UsersRepository}; use imphnen_libs::AppState; use imphnen_utils::{common_response, extract_email}; use std::convert::Infallible; @@ -23,7 +23,7 @@ pub async fn auth_middleware( } }; let repository = UsersRepository::new(&state); - let user: Option = + let user: Option = match repository.query_user_by_email(email).await { Ok(user) => Some(user), Err(err) => { diff --git a/tests/src/iam/auth/auth_repository_test.rs b/tests/src/iam/auth/auth_repository_test.rs index c16026d..f7dce4b 100644 --- a/tests/src/iam/auth/auth_repository_test.rs +++ b/tests/src/iam/auth/auth_repository_test.rs @@ -1,10 +1,11 @@ #[cfg(test)] mod auth_repository_test { use crate::{ - create_mock_app_state, get_iso_date, make_thing, AuthOtpSchema, AuthRepository, - ResourceEnum, RolesItemDtoRaw, UsersItemDtoRaw, UsersRepository, UsersSchema, + AuthOtpSchema, AuthRepository, ResourceEnum, UsersRepository, UsersSchema, + create_mock_app_state, get_iso_date, make_thing, }; use chrono::{Duration, Utc}; + use imphnen_iam::{RolesDetailQueryDto, UsersDetailQueryDto}; use surrealdb::Uuid; fn create_mock_user(email: &str) -> UsersSchema { @@ -47,7 +48,7 @@ mod auth_repository_test { let state = create_mock_app_state().await; let auth_repo = AuthRepository::new(&state); let email = "delete_me@example.com".to_string(); - let mock_user = UsersItemDtoRaw { + let mock_user = UsersDetailQueryDto { id: make_thing(&ResourceEnum::UsersCache.to_string(), &email), fullname: "Test User".into(), email: email.clone(), @@ -56,7 +57,7 @@ mod auth_repository_test { is_active: true, gender: None, birthdate: None, - role: RolesItemDtoRaw { + role: RolesDetailQueryDto { id: make_thing("app_roles", &Uuid::new_v4().to_string()), name: "Dummy Role".into(), permissions: vec![], @@ -69,7 +70,7 @@ mod auth_repository_test { created_at: get_iso_date(), updated_at: get_iso_date(), }; - let _: Option = state + let _: Option = state .surrealdb_mem .create((ResourceEnum::UsersCache.to_string(), email.clone())) .content(mock_user) diff --git a/tests/src/iam/roles/roles_controller_test.rs b/tests/src/iam/roles/roles_controller_test.rs index 937e177..3979817 100644 --- a/tests/src/iam/roles/roles_controller_test.rs +++ b/tests/src/iam/roles/roles_controller_test.rs @@ -1,11 +1,11 @@ use crate::AppState; use crate::{ - create_mock_app_state, roles_router, v1::roles_repository::RolesRepository, - RolesRequestCreateDto, RolesRequestUpdateDto, + RolesRequestCreateDto, RolesRequestUpdateDto, create_mock_app_state, roles_router, + v1::roles_repository::RolesRepository, }; -use axum::http::StatusCode; use axum::Extension; use axum::Router; +use axum::http::StatusCode; use axum_test::TestServer; pub fn create_test_app(state: AppState) -> TestServer { @@ -74,6 +74,7 @@ async fn test_put_update_role_should_return_200() { let payload = RolesRequestUpdateDto { name: Some("Updated Role".into()), permissions: Some(vec![]), + overwrite: None, }; let res = server .put(&format!("/v1/roles/update/{}", id)) @@ -131,6 +132,7 @@ async fn test_put_update_nonexistent_role_should_return_404() { let payload = RolesRequestUpdateDto { name: Some("Does Not Exist".into()), permissions: Some(vec![]), + overwrite: None, }; let res = server .put("/v1/roles/update/nonexistent-id") diff --git a/tests/src/iam/roles/roles_repository_test.rs b/tests/src/iam/roles/roles_repository_test.rs index a7de09e..adcea17 100644 --- a/tests/src/iam/roles/roles_repository_test.rs +++ b/tests/src/iam/roles/roles_repository_test.rs @@ -100,6 +100,7 @@ async fn test_query_update_role_should_update_name_and_permissions() { let update_payload = RolesRequestUpdateDto { name: Some("Updated Role Name".into()), permissions: Some(vec![new_perm_id.clone()]), + overwrite: None, }; let update_result = repo .query_update_role(existing_role_id.clone(), update_payload) @@ -158,6 +159,7 @@ async fn test_query_update_role_should_fallback_to_existing_permissions_if_none_ let update_payload = RolesRequestUpdateDto { name: Some("Updated Role Name".into()), permissions: None, + overwrite: None, }; let update_res = repo .query_update_role(existing_id.clone(), update_payload) diff --git a/tests/src/iam/users/users_repository_test.rs b/tests/src/iam/users/users_repository_test.rs index 3b9fbb3..ff1b9cd 100644 --- a/tests/src/iam/users/users_repository_test.rs +++ b/tests/src/iam/users/users_repository_test.rs @@ -1,8 +1,5 @@ -use crate::{create_mock_app_state, create_test_user, RolesRepository}; -use crate::{ - MetaRequestDto, UsersActiveInactiveSchema, UsersRepository, - UsersSetNewPasswordSchema, -}; +use crate::{MetaRequestDto, UsersRepository}; +use crate::{RolesRepository, create_mock_app_state, create_test_user}; async fn get_role_id(state: &crate::AppState) -> String { RolesRepository::new(state) @@ -31,35 +28,6 @@ async fn test_create_and_get_user() { assert_eq!(fetched.unwrap().email, "testuser@example.com"); } -#[tokio::test] -async fn test_update_password_user() { - let app_state = create_mock_app_state().await; - let repo = UsersRepository::new(&app_state); - let role_repo = RolesRepository::new(&app_state); - let role_id = role_repo - .query_role_by_name("Student".into()) - .await - .expect("Role not found") - .id; - let email = "changepass@example.com"; - let user = create_test_user(email, "Change Password", true, &role_id); - repo.query_create_user(user).await.unwrap(); - let result = repo - .query_update_password_user( - email.to_string(), - UsersSetNewPasswordSchema { - password: "newpass".into(), - }, - ) - .await; - assert!( - result.is_ok(), - "Update password failed with error: {:?}", - result.err() - ); - dbg!(result.unwrap()); -} - #[tokio::test] async fn test_query_user_list_with_pagination_and_filter() { let app_state = create_mock_app_state().await; @@ -116,57 +84,6 @@ async fn test_query_user_list_basic() { assert_eq!(result.meta.as_ref().unwrap().per_page.unwrap(), 5); } -#[tokio::test] -async fn test_query_active_inactive_user() { - let app_state = create_mock_app_state().await; - let repo = UsersRepository::new(&app_state); - let email = "inactive@example.com"; - let user = create_test_user( - email, - "Inactive User", - false, - &get_role_id(&app_state).await, - ); - repo.query_create_user(user).await.unwrap(); - let result = repo - .query_active_inactive_user( - email.into(), - UsersActiveInactiveSchema { is_active: true }, - ) - .await; - assert!(result.is_ok()); - let updated = repo - .query_user_by_email("inactive@example.com".into()) - .await - .unwrap(); - assert_eq!(updated.is_active, true); -} - -#[tokio::test] -async fn test_query_user_by_invalid_email_should_fail() { - let app_state = create_mock_app_state().await; - let repo = UsersRepository::new(&app_state); - let result = repo - .query_user_by_email("nonexistent@example.com".into()) - .await; - assert!(result.is_err()); -} - -#[tokio::test] -async fn test_query_update_password_for_nonexistent_user_should_fail() { - let app_state = create_mock_app_state().await; - let repo = UsersRepository::new(&app_state); - let result = repo - .query_update_password_user( - "ghost@example.com".into(), - UsersSetNewPasswordSchema { - password: "secret".into(), - }, - ) - .await; - assert!(result.is_err()); -} - #[tokio::test] async fn test_query_delete_user() { let app_state = create_mock_app_state().await; diff --git a/tests/src/lib.rs b/tests/src/lib.rs index eded98f..863596d 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,6 +1,5 @@ pub use imphnen_entities::*; pub use imphnen_iam::*; -pub use imphnen_utils::*; #[cfg(test)] pub mod iam;