chore: cleaning code
This commit is contained in:
@@ -25,8 +25,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
(
|
(
|
||||||
"0269ed71-0ae0-4c43-ad29-e3d861d8f9a0",
|
"0269ed71-0ae0-4c43-ad29-e3d861d8f9a0",
|
||||||
"Create Permissions",
|
"Create Permissions",
|
||||||
None,
|
Some("2025-01-29T05:11:01.265+00"),
|
||||||
None,
|
Some("2025-01-29T05:11:01.265001+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b",
|
"299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b",
|
||||||
@@ -37,20 +37,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
(
|
(
|
||||||
"319ee593-ff0a-4f29-bbaf-9feb3174a3a2",
|
"319ee593-ff0a-4f29-bbaf-9feb3174a3a2",
|
||||||
"Create Roles",
|
"Create Roles",
|
||||||
None,
|
Some("2025-01-29T05:11:01.265+00"),
|
||||||
None,
|
Some("2025-01-29T05:11:01.265001+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"319ee593-ff0a-4f29-bbaf-9feb3174a3a6",
|
"319ee593-ff0a-4f29-bbaf-9feb3174a3a6",
|
||||||
"Read Detail Users",
|
"Read Detail Users",
|
||||||
None,
|
Some("2025-01-29T05:11:01.265+00"),
|
||||||
None,
|
Some("2025-01-29T05:11:01.265001+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"35b0d992-65c8-4b62-b030-e6e0320e4048",
|
"35b0d992-65c8-4b62-b030-e6e0320e4048",
|
||||||
"Delete Roles",
|
"Delete Roles",
|
||||||
None,
|
Some("2025-01-29T05:34:40.621554+00"),
|
||||||
None,
|
Some("2025-01-29T05:34:40.621555+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"4da8b434-89f9-4d91-85ae-eebd63cdbeda",
|
"4da8b434-89f9-4d91-85ae-eebd63cdbeda",
|
||||||
@@ -91,8 +91,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
(
|
(
|
||||||
"9164ca6e-c7e3-4238-a15f-f36ab9577e7e",
|
"9164ca6e-c7e3-4238-a15f-f36ab9577e7e",
|
||||||
"Read List Roles",
|
"Read List Roles",
|
||||||
None,
|
Some("2025-01-29T05:34:40.621554+00"),
|
||||||
None,
|
Some("2025-01-29T05:34:40.621555+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"96df0689-2ae9-4894-bf00-837c19415e5c",
|
"96df0689-2ae9-4894-bf00-837c19415e5c",
|
||||||
@@ -109,8 +109,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
(
|
(
|
||||||
"a00d5608-4c48-4542-845c-dfe004687022",
|
"a00d5608-4c48-4542-845c-dfe004687022",
|
||||||
"Update Roles",
|
"Update Roles",
|
||||||
None,
|
Some("2025-01-29T05:34:40.621554+00"),
|
||||||
None,
|
Some("2025-01-29T05:34:40.621555+00"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"b2dc3928-86ba-4c59-a03d-0b57d5183ebc",
|
"b2dc3928-86ba-4c59-a03d-0b57d5183ebc",
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ impl<'a> GachaItemRepository<'a> {
|
|||||||
&meta,
|
&meta,
|
||||||
conditions,
|
conditions,
|
||||||
None,
|
None,
|
||||||
|
"name",
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use imphnen_iam::{
|
use imphnen_iam::{
|
||||||
auth, permissions, roles, users, AuthLoginRequestDto, AuthLoginResponsetDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto,
|
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
|
||||||
AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsItemDto, PermissionsRequestDto, ResponseListSuccessDto, ResponseSuccessDto, RolesItemDto, RolesRequestCreateDto, RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto, UsersItemDto, UsersListItemDto, UsersUpdateRequestDto
|
|
||||||
};
|
};
|
||||||
use utoipa::{
|
use utoipa::{
|
||||||
openapi::security::{Http, HttpAuthScheme, SecurityScheme},
|
openapi::security::{Http, HttpAuthScheme, SecurityScheme},
|
||||||
@@ -48,18 +47,18 @@ use utoipa::{
|
|||||||
AuthNewPasswordRequestDto,
|
AuthNewPasswordRequestDto,
|
||||||
AuthRefreshTokenRequestDto,
|
AuthRefreshTokenRequestDto,
|
||||||
ResponseSuccessDto<TokenDto>,
|
ResponseSuccessDto<TokenDto>,
|
||||||
RolesItemDto,
|
RolesListItemDto,
|
||||||
RolesRequestCreateDto,
|
RolesRequestCreateDto,
|
||||||
RolesRequestUpdateDto,
|
RolesRequestUpdateDto,
|
||||||
PermissionsRequestDto,
|
PermissionsRequestDto,
|
||||||
PermissionsItemDto,
|
PermissionsItemDto,
|
||||||
UsersItemDto,
|
UsersDetailItemDto,
|
||||||
UsersListItemDto,
|
UsersListItemDto,
|
||||||
UsersUpdateRequestDto,
|
UsersUpdateRequestDto,
|
||||||
UsersCreateRequestDto,
|
UsersCreateRequestDto,
|
||||||
ResponseSuccessDto<AuthLoginResponsetDto>,
|
ResponseSuccessDto<AuthLoginResponsetDto>,
|
||||||
ResponseListSuccessDto<Vec<RolesItemDto>>,
|
ResponseListSuccessDto<Vec<RolesListItemDto>>,
|
||||||
ResponseSuccessDto<RolesItemDto>,
|
ResponseSuccessDto<RolesDetailItemDto>,
|
||||||
ResponseListSuccessDto<Vec<UsersListItemDto>>,
|
ResponseListSuccessDto<Vec<UsersListItemDto>>,
|
||||||
ResponseSuccessDto<UsersDetailItemDto>,
|
ResponseSuccessDto<UsersDetailItemDto>,
|
||||||
ResponseListSuccessDto<Vec<PermissionsItemDto>>,
|
ResponseListSuccessDto<Vec<PermissionsItemDto>>,
|
||||||
|
|||||||
@@ -1,25 +1,29 @@
|
|||||||
use crate::RolesItemDto;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
use validator::{Validate, ValidationError};
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
|
use crate::UsersDetailItemDto;
|
||||||
|
|
||||||
lazy_static! {
|
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> {
|
fn validate_password_complexity(password: &str) -> Result<(), ValidationError> {
|
||||||
let has_uppercase = password.chars().any(|c| c.is_ascii_uppercase());
|
let has_uppercase = password.chars().any(|c| c.is_ascii_uppercase());
|
||||||
let has_lowercase = password.chars().any(|c| c.is_ascii_lowercase());
|
let has_lowercase = password.chars().any(|c| c.is_ascii_lowercase());
|
||||||
let has_digit = password.chars().any(|c| c.is_ascii_digit());
|
let has_digit = password.chars().any(|c| c.is_ascii_digit());
|
||||||
let has_special = password.chars().any(|c| "@$!%*?&".contains(c));
|
let has_special = password.chars().any(|c| "@$!%*?&".contains(c));
|
||||||
|
|
||||||
if has_uppercase && has_lowercase && has_digit && has_special {
|
if has_uppercase && has_lowercase && has_digit && has_special {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::new("complexity"))
|
Err(ValidationError::new("complexity"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)]
|
||||||
@@ -33,23 +37,10 @@ pub struct AuthLoginRequestDto {
|
|||||||
pub password: String,
|
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<String>,
|
|
||||||
pub phone_number: String,
|
|
||||||
pub is_active: bool,
|
|
||||||
pub gender: Option<String>,
|
|
||||||
pub birthdate: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||||
pub struct AuthLoginResponsetDto {
|
pub struct AuthLoginResponsetDto {
|
||||||
pub token: TokenDto,
|
pub token: TokenDto,
|
||||||
pub user: AuthUserItemDto,
|
pub user: UsersDetailItemDto,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||||
@@ -77,28 +68,7 @@ pub struct AuthRegisterRequestDto {
|
|||||||
#[validate(length(min = 2, message = "Fullname at least have 2 character"))]
|
#[validate(length(min = 2, message = "Fullname at least have 2 character"))]
|
||||||
pub fullname: String,
|
pub fullname: String,
|
||||||
#[validate(length(min = 1, message = "Student type is required"))]
|
#[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,
|
pub phone_number: String,
|
||||||
#[validate(length(
|
|
||||||
max = 4,
|
|
||||||
message = "Referal code cannot be more than 4 character"
|
|
||||||
))]
|
|
||||||
pub referral_code: Option<String>,
|
|
||||||
pub referred_by: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::AuthOtpSchema;
|
use super::AuthOtpSchema;
|
||||||
use crate::{make_thing, AppState, ResourceEnum, UsersItemDtoRaw};
|
use crate::{AppState, ResourceEnum, UsersDetailQueryDto, make_thing};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{Result, anyhow, bail};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
|
|
||||||
pub struct AuthRepository<'a> {
|
pub struct AuthRepository<'a> {
|
||||||
@@ -12,7 +12,7 @@ impl<'a> AuthRepository<'a> {
|
|||||||
Self { state }
|
Self { state }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn query_store_user(&self, user: UsersItemDtoRaw) -> Result<String> {
|
pub async fn query_store_user(&self, user: UsersDetailQueryDto) -> Result<String> {
|
||||||
if user.email.trim().is_empty() {
|
if user.email.trim().is_empty() {
|
||||||
bail!("Email is required");
|
bail!("Email is required");
|
||||||
}
|
}
|
||||||
@@ -22,11 +22,11 @@ impl<'a> AuthRepository<'a> {
|
|||||||
let _ = self
|
let _ = self
|
||||||
.state
|
.state
|
||||||
.surrealdb_mem
|
.surrealdb_mem
|
||||||
.delete::<Option<UsersItemDtoRaw>>((table.clone(), user_id.clone()))
|
.delete::<Option<UsersDetailQueryDto>>((table.clone(), user_id.clone()))
|
||||||
.await?;
|
.await?;
|
||||||
let mut user_to_store = user.clone();
|
let mut user_to_store = user.clone();
|
||||||
user_to_store.id = id.clone();
|
user_to_store.id = id.clone();
|
||||||
let record: Option<UsersItemDtoRaw> = self
|
let record: Option<UsersDetailQueryDto> = self
|
||||||
.state
|
.state
|
||||||
.surrealdb_mem
|
.surrealdb_mem
|
||||||
.create((table, user_id))
|
.create((table, user_id))
|
||||||
@@ -41,8 +41,8 @@ impl<'a> AuthRepository<'a> {
|
|||||||
pub async fn query_get_stored_user(
|
pub async fn query_get_stored_user(
|
||||||
&self,
|
&self,
|
||||||
email: String,
|
email: String,
|
||||||
) -> Result<UsersItemDtoRaw> {
|
) -> Result<UsersDetailQueryDto> {
|
||||||
let user: Option<UsersItemDtoRaw> = self
|
let user: Option<UsersDetailQueryDto> = self
|
||||||
.state
|
.state
|
||||||
.surrealdb_mem
|
.surrealdb_mem
|
||||||
.select((ResourceEnum::UsersCache.to_string(), email))
|
.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<String> {
|
pub async fn query_delete_stored_user(&self, email: String) -> Result<String> {
|
||||||
let record: Option<UsersItemDtoRaw> = self
|
let record: Option<UsersDetailQueryDto> = self
|
||||||
.state
|
.state
|
||||||
.surrealdb_mem
|
.surrealdb_mem
|
||||||
.delete((ResourceEnum::UsersCache.to_string(), email))
|
.delete((ResourceEnum::UsersCache.to_string(), email))
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use super::{
|
use super::{
|
||||||
AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto,
|
AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto,
|
||||||
AuthRefreshTokenRequestDto, AuthRegisterRequestDto, AuthRepository,
|
AuthRefreshTokenRequestDto, AuthRegisterRequestDto, AuthRepository,
|
||||||
AuthResendOtpRequestDto, AuthUserItemDto, AuthVerifyEmailRequestDto, TokenDto,
|
AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, TokenDto,
|
||||||
};
|
};
|
||||||
use crate::{
|
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,
|
encode_reset_password_token, extract_email_token, generate_otp, get_iso_date,
|
||||||
hash_password, make_thing, send_email, success_response, validate_request,
|
hash_password, make_thing, send_email, success_response, validate_request,
|
||||||
verify_password, AppState, Env, ResourceEnum, ResponseSuccessDto, RolesEnum,
|
verify_password,
|
||||||
RolesItemDto, RolesRepository, UsersActiveInactiveSchema, UsersRepository,
|
|
||||||
UsersSchema, UsersSetNewPasswordSchema,
|
|
||||||
};
|
};
|
||||||
use axum::{http::StatusCode, response::Response};
|
use axum::{http::StatusCode, response::Response};
|
||||||
use surrealdb::Uuid;
|
use surrealdb::Uuid;
|
||||||
@@ -27,7 +27,6 @@ impl AuthService {
|
|||||||
|
|
||||||
let user_repo = UsersRepository::new(state);
|
let user_repo = UsersRepository::new(state);
|
||||||
let auth_repo = AuthRepository::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 {
|
match user_repo.query_user_by_email(payload.email.clone()).await {
|
||||||
Ok(user) => {
|
Ok(user) => {
|
||||||
@@ -54,7 +53,7 @@ impl AuthService {
|
|||||||
return common_response(
|
return common_response(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"Failed to generate access token",
|
"Failed to generate access token",
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,34 +63,13 @@ impl AuthService {
|
|||||||
return common_response(
|
return common_response(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"Failed to generate refresh token",
|
"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 {
|
let response = ResponseSuccessDto {
|
||||||
data: AuthLoginResponsetDto {
|
data: AuthLoginResponsetDto {
|
||||||
user: AuthUserItemDto {
|
user: UsersDetailItemDto::from(&user),
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
token: TokenDto {
|
token: TokenDto {
|
||||||
access_token,
|
access_token,
|
||||||
refresh_token,
|
refresh_token,
|
||||||
@@ -116,6 +94,7 @@ impl AuthService {
|
|||||||
if let Err((status, message)) = validate_request(&payload) {
|
if let Err((status, message)) = validate_request(&payload) {
|
||||||
return common_response(status, &message);
|
return common_response(status, &message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_repo = UsersRepository::new(state);
|
let user_repo = UsersRepository::new(state);
|
||||||
let auth_repo = AuthRepository::new(state);
|
let auth_repo = AuthRepository::new(state);
|
||||||
let role_repo = RolesRepository::new(state);
|
let role_repo = RolesRepository::new(state);
|
||||||
@@ -126,6 +105,7 @@ impl AuthService {
|
|||||||
Ok(role) => role,
|
Ok(role) => role,
|
||||||
Err(_) => return common_response(StatusCode::BAD_REQUEST, "Role Not Found"),
|
Err(_) => return common_response(StatusCode::BAD_REQUEST, "Role Not Found"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if user_repo
|
if user_repo
|
||||||
.query_user_by_email(payload.email.clone())
|
.query_user_by_email(payload.email.clone())
|
||||||
.await
|
.await
|
||||||
@@ -133,6 +113,7 @@ impl AuthService {
|
|||||||
{
|
{
|
||||||
return common_response(StatusCode::BAD_REQUEST, "User already exists");
|
return common_response(StatusCode::BAD_REQUEST, "User already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
let hashed_password = match hash_password(&payload.password) {
|
let hashed_password = match hash_password(&payload.password) {
|
||||||
Ok(hash) => hash,
|
Ok(hash) => hash,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -142,16 +123,16 @@ impl AuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_user = AuthRegisterRequestDto {
|
let new_user = AuthRegisterRequestDto {
|
||||||
email: payload.email,
|
email: payload.email,
|
||||||
password: hashed_password,
|
password: hashed_password,
|
||||||
fullname: payload.fullname,
|
fullname: payload.fullname,
|
||||||
student_type: payload.student_type,
|
|
||||||
phone_number: payload.phone_number,
|
phone_number: payload.phone_number,
|
||||||
referral_code: payload.referral_code,
|
|
||||||
referred_by: payload.referred_by,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let otp = generate_otp::OtpManager::generate_otp();
|
let otp = generate_otp::OtpManager::generate_otp();
|
||||||
|
|
||||||
match auth_repo
|
match auth_repo
|
||||||
.query_store_otp(new_user.email.clone(), otp.clone())
|
.query_store_otp(new_user.email.clone(), otp.clone())
|
||||||
.await
|
.await
|
||||||
@@ -169,11 +150,13 @@ impl AuthService {
|
|||||||
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string());
|
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let role_thing = make_thing(&ResourceEnum::Roles.to_string(), &role.id);
|
let role_thing = make_thing(&ResourceEnum::Roles.to_string(), &role.id);
|
||||||
let user_thing = make_thing(
|
let user_thing = make_thing(
|
||||||
&ResourceEnum::Users.to_string(),
|
&ResourceEnum::Users.to_string(),
|
||||||
&Uuid::new_v4().to_string(),
|
&Uuid::new_v4().to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
match user_repo
|
match user_repo
|
||||||
.query_create_user(UsersSchema {
|
.query_create_user(UsersSchema {
|
||||||
id: user_thing,
|
id: user_thing,
|
||||||
@@ -202,14 +185,18 @@ impl AuthService {
|
|||||||
if let Err((status, message)) = validate_request(&payload) {
|
if let Err((status, message)) = validate_request(&payload) {
|
||||||
return common_response(status, &message);
|
return common_response(status, &message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let user_repo = UsersRepository::new(state);
|
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");
|
return common_response(StatusCode::BAD_REQUEST, "User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
let auth_repo = AuthRepository::new(state);
|
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 otp = generate_otp::OtpManager::generate_otp();
|
||||||
let message = format!("Your OTP code is {}", otp);
|
let message = format!("Your OTP code is {}", otp);
|
||||||
@@ -273,10 +260,10 @@ impl AuthService {
|
|||||||
let user = match user_result {
|
let user = match user_result {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(err) if err.to_string().contains("User not found") => {
|
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) => {
|
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) {
|
let token = match encode_reset_password_token(user.email) {
|
||||||
@@ -285,7 +272,7 @@ impl AuthService {
|
|||||||
return common_response(
|
return common_response(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
"Failed to generate access token",
|
"Failed to generate access token",
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let env = Env::new();
|
let env = Env::new();
|
||||||
@@ -310,15 +297,18 @@ impl AuthService {
|
|||||||
let user_repo = UsersRepository::new(state);
|
let user_repo = UsersRepository::new(state);
|
||||||
let auth_repo = AuthRepository::new(state);
|
let auth_repo = AuthRepository::new(state);
|
||||||
let email = payload.email.clone();
|
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 {
|
match auth_repo.query_get_stored_otp(email.clone()).await {
|
||||||
Ok(stored_otp) => match stored_otp == payload.otp {
|
Ok(stored_otp) => match stored_otp == payload.otp {
|
||||||
true => match user_repo
|
true => match user_repo.query_update_user(patch).await {
|
||||||
.query_active_inactive_user(
|
|
||||||
email.clone(),
|
|
||||||
UsersActiveInactiveSchema { is_active: true },
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => match auth_repo.query_delete_stored_otp(email).await {
|
Ok(_) => match auth_repo.query_delete_stored_otp(email).await {
|
||||||
Ok(_) => common_response(StatusCode::OK, "Email verified successfully"),
|
Ok(_) => common_response(StatusCode::OK, "Email verified successfully"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -346,7 +336,7 @@ impl AuthService {
|
|||||||
if let Err((status, message)) = validate_request(&payload) {
|
if let Err((status, message)) = validate_request(&payload) {
|
||||||
return common_response(status, &message);
|
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()) {
|
let email = match extract_email_token(payload.token.clone()) {
|
||||||
Some(email) => email,
|
Some(email) => email,
|
||||||
None => {
|
None => {
|
||||||
@@ -362,12 +352,18 @@ impl AuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match user_repo
|
let user = match repo.query_user_by_email(email.clone()).await {
|
||||||
.query_update_password_user(email, UsersSetNewPasswordSchema { password })
|
Ok(user) if !user.is_deleted => user,
|
||||||
.await
|
_ => 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),
|
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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use super::{PermissionsItemDto, PermissionsItemDtoRaw, PermissionsSchema};
|
use super::{PermissionsItemDto, PermissionsSchema};
|
||||||
use crate::{
|
use crate::{
|
||||||
get_id, make_thing, query_list_with_meta, AppState, MetaRequestDto, ResourceEnum,
|
AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto, get_id,
|
||||||
ResponseListSuccessDto,
|
make_thing, query_list_with_meta,
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{Result, bail};
|
||||||
use imphnen_utils::extract_id;
|
use imphnen_utils::extract_id;
|
||||||
|
|
||||||
pub struct PermissionsRepository<'a> {
|
pub struct PermissionsRepository<'a> {
|
||||||
@@ -27,14 +27,17 @@ impl<'a> PermissionsRepository<'a> {
|
|||||||
let filter_by = meta.filter_by.as_ref().unwrap();
|
let filter_by = meta.filter_by.as_ref().unwrap();
|
||||||
conditions.push(format!("{} = $filter", filter_by));
|
conditions.push(format!("{} = $filter", filter_by));
|
||||||
}
|
}
|
||||||
let raw_result: ResponseListSuccessDto<Vec<PermissionsItemDtoRaw>> = query_list_with_meta(
|
let raw_result: ResponseListSuccessDto<Vec<PermissionsSchema>> =
|
||||||
&self.state.surrealdb_ws,
|
query_list_with_meta(
|
||||||
&ResourceEnum::Permissions.to_string(),
|
&self.state.surrealdb_ws,
|
||||||
&meta,
|
&ResourceEnum::Permissions.to_string(),
|
||||||
conditions,
|
&meta,
|
||||||
None,
|
conditions,
|
||||||
)
|
None,
|
||||||
.await?;
|
"name",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let transformed_data = raw_result
|
let transformed_data = raw_result
|
||||||
.data
|
.data
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -69,9 +72,7 @@ impl<'a> PermissionsRepository<'a> {
|
|||||||
&self,
|
&self,
|
||||||
id: String,
|
id: String,
|
||||||
) -> Result<PermissionsItemDto> {
|
) -> Result<PermissionsItemDto> {
|
||||||
let raw_result = self
|
let raw_result = self.query_permission_by_id(id.clone()).await?;
|
||||||
.query_permission_by_id(id.clone())
|
|
||||||
.await?;
|
|
||||||
let transformed_data = PermissionsItemDto {
|
let transformed_data = PermissionsItemDto {
|
||||||
id: extract_id(&raw_result.id),
|
id: extract_id(&raw_result.id),
|
||||||
name: raw_result.name,
|
name: raw_result.name,
|
||||||
@@ -81,7 +82,6 @@ impl<'a> PermissionsRepository<'a> {
|
|||||||
Ok(transformed_data)
|
Ok(transformed_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn query_permission_by_name(
|
pub async fn query_permission_by_name(
|
||||||
&self,
|
&self,
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{make_thing, ResourceEnum};
|
use crate::{ResourceEnum, make_thing};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::{sql::Thing, Uuid};
|
use surrealdb::{Uuid, sql::Thing};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct PermissionsSchema {
|
pub struct PermissionsSchema {
|
||||||
|
|||||||
@@ -95,19 +95,19 @@ pub struct UsersDetailItemDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UsersDetailItemDto {
|
impl UsersDetailItemDto {
|
||||||
pub fn from(dto: UsersDetailQueryDto) -> Self {
|
pub fn from(dto: &UsersDetailQueryDto) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: dto.id.id.to_raw(),
|
id: dto.id.id.to_raw().clone(),
|
||||||
role: RolesDetailItemDto::from(&dto.role),
|
role: RolesDetailItemDto::from(&dto.role),
|
||||||
fullname: dto.fullname,
|
fullname: dto.fullname.clone(),
|
||||||
email: dto.email,
|
email: dto.email.clone(),
|
||||||
avatar: dto.avatar,
|
avatar: dto.avatar.clone(),
|
||||||
phone_number: dto.phone_number,
|
phone_number: dto.phone_number.clone(),
|
||||||
is_active: dto.is_active,
|
is_active: dto.is_active.clone(),
|
||||||
gender: dto.gender,
|
gender: dto.gender.clone(),
|
||||||
birthdate: dto.birthdate,
|
birthdate: dto.birthdate.clone(),
|
||||||
created_at: dto.created_at,
|
created_at: dto.created_at.clone(),
|
||||||
updated_at: dto.updated_at,
|
updated_at: dto.updated_at.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl UsersService {
|
|||||||
let repo = UsersRepository::new(state);
|
let repo = UsersRepository::new(state);
|
||||||
match repo.query_user_by_id(id).await {
|
match repo.query_user_by_id(id).await {
|
||||||
Ok(user) if !user.is_deleted => success_response(ResponseSuccessDto {
|
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"),
|
Ok(_) => common_response(StatusCode::NOT_FOUND, "User not found"),
|
||||||
Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()),
|
Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()),
|
||||||
@@ -49,7 +49,7 @@ impl UsersService {
|
|||||||
};
|
};
|
||||||
match repo.query_user_by_email(email).await {
|
match repo.query_user_by_email(email).await {
|
||||||
Ok(user) if !user.is_deleted => success_response(ResponseSuccessDto {
|
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"),
|
Ok(_) => common_response(StatusCode::NOT_FOUND, "User not found"),
|
||||||
Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()),
|
Err(e) => common_response(StatusCode::NOT_FOUND, &e.to_string()),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use axum::{
|
|||||||
Extension, extract::Request, http::StatusCode, middleware::Next,
|
Extension, extract::Request, http::StatusCode, middleware::Next,
|
||||||
response::Response,
|
response::Response,
|
||||||
};
|
};
|
||||||
use imphnen_iam::{UsersItemDtoRaw, UsersRepository};
|
use imphnen_iam::{UsersDetailQueryDto, UsersRepository};
|
||||||
use imphnen_libs::AppState;
|
use imphnen_libs::AppState;
|
||||||
use imphnen_utils::{common_response, extract_email};
|
use imphnen_utils::{common_response, extract_email};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
@@ -23,7 +23,7 @@ pub async fn auth_middleware(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let repository = UsersRepository::new(&state);
|
let repository = UsersRepository::new(&state);
|
||||||
let user: Option<UsersItemDtoRaw> =
|
let user: Option<UsersDetailQueryDto> =
|
||||||
match repository.query_user_by_email(email).await {
|
match repository.query_user_by_email(email).await {
|
||||||
Ok(user) => Some(user),
|
Ok(user) => Some(user),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod auth_repository_test {
|
mod auth_repository_test {
|
||||||
use crate::{
|
use crate::{
|
||||||
create_mock_app_state, get_iso_date, make_thing, AuthOtpSchema, AuthRepository,
|
AuthOtpSchema, AuthRepository, ResourceEnum, UsersRepository, UsersSchema,
|
||||||
ResourceEnum, RolesItemDtoRaw, UsersItemDtoRaw, UsersRepository, UsersSchema,
|
create_mock_app_state, get_iso_date, make_thing,
|
||||||
};
|
};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
|
use imphnen_iam::{RolesDetailQueryDto, UsersDetailQueryDto};
|
||||||
use surrealdb::Uuid;
|
use surrealdb::Uuid;
|
||||||
|
|
||||||
fn create_mock_user(email: &str) -> UsersSchema {
|
fn create_mock_user(email: &str) -> UsersSchema {
|
||||||
@@ -47,7 +48,7 @@ mod auth_repository_test {
|
|||||||
let state = create_mock_app_state().await;
|
let state = create_mock_app_state().await;
|
||||||
let auth_repo = AuthRepository::new(&state);
|
let auth_repo = AuthRepository::new(&state);
|
||||||
let email = "delete_me@example.com".to_string();
|
let email = "delete_me@example.com".to_string();
|
||||||
let mock_user = UsersItemDtoRaw {
|
let mock_user = UsersDetailQueryDto {
|
||||||
id: make_thing(&ResourceEnum::UsersCache.to_string(), &email),
|
id: make_thing(&ResourceEnum::UsersCache.to_string(), &email),
|
||||||
fullname: "Test User".into(),
|
fullname: "Test User".into(),
|
||||||
email: email.clone(),
|
email: email.clone(),
|
||||||
@@ -56,7 +57,7 @@ mod auth_repository_test {
|
|||||||
is_active: true,
|
is_active: true,
|
||||||
gender: None,
|
gender: None,
|
||||||
birthdate: None,
|
birthdate: None,
|
||||||
role: RolesItemDtoRaw {
|
role: RolesDetailQueryDto {
|
||||||
id: make_thing("app_roles", &Uuid::new_v4().to_string()),
|
id: make_thing("app_roles", &Uuid::new_v4().to_string()),
|
||||||
name: "Dummy Role".into(),
|
name: "Dummy Role".into(),
|
||||||
permissions: vec![],
|
permissions: vec![],
|
||||||
@@ -69,7 +70,7 @@ mod auth_repository_test {
|
|||||||
created_at: get_iso_date(),
|
created_at: get_iso_date(),
|
||||||
updated_at: get_iso_date(),
|
updated_at: get_iso_date(),
|
||||||
};
|
};
|
||||||
let _: Option<UsersItemDtoRaw> = state
|
let _: Option<UsersDetailQueryDto> = state
|
||||||
.surrealdb_mem
|
.surrealdb_mem
|
||||||
.create((ResourceEnum::UsersCache.to_string(), email.clone()))
|
.create((ResourceEnum::UsersCache.to_string(), email.clone()))
|
||||||
.content(mock_user)
|
.content(mock_user)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use crate::{
|
use crate::{
|
||||||
create_mock_app_state, roles_router, v1::roles_repository::RolesRepository,
|
RolesRequestCreateDto, RolesRequestUpdateDto, create_mock_app_state, roles_router,
|
||||||
RolesRequestCreateDto, RolesRequestUpdateDto,
|
v1::roles_repository::RolesRepository,
|
||||||
};
|
};
|
||||||
use axum::http::StatusCode;
|
|
||||||
use axum::Extension;
|
use axum::Extension;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
use axum::http::StatusCode;
|
||||||
use axum_test::TestServer;
|
use axum_test::TestServer;
|
||||||
|
|
||||||
pub fn create_test_app(state: AppState) -> 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 {
|
let payload = RolesRequestUpdateDto {
|
||||||
name: Some("Updated Role".into()),
|
name: Some("Updated Role".into()),
|
||||||
permissions: Some(vec![]),
|
permissions: Some(vec![]),
|
||||||
|
overwrite: None,
|
||||||
};
|
};
|
||||||
let res = server
|
let res = server
|
||||||
.put(&format!("/v1/roles/update/{}", id))
|
.put(&format!("/v1/roles/update/{}", id))
|
||||||
@@ -131,6 +132,7 @@ async fn test_put_update_nonexistent_role_should_return_404() {
|
|||||||
let payload = RolesRequestUpdateDto {
|
let payload = RolesRequestUpdateDto {
|
||||||
name: Some("Does Not Exist".into()),
|
name: Some("Does Not Exist".into()),
|
||||||
permissions: Some(vec![]),
|
permissions: Some(vec![]),
|
||||||
|
overwrite: None,
|
||||||
};
|
};
|
||||||
let res = server
|
let res = server
|
||||||
.put("/v1/roles/update/nonexistent-id")
|
.put("/v1/roles/update/nonexistent-id")
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ async fn test_query_update_role_should_update_name_and_permissions() {
|
|||||||
let update_payload = RolesRequestUpdateDto {
|
let update_payload = RolesRequestUpdateDto {
|
||||||
name: Some("Updated Role Name".into()),
|
name: Some("Updated Role Name".into()),
|
||||||
permissions: Some(vec![new_perm_id.clone()]),
|
permissions: Some(vec![new_perm_id.clone()]),
|
||||||
|
overwrite: None,
|
||||||
};
|
};
|
||||||
let update_result = repo
|
let update_result = repo
|
||||||
.query_update_role(existing_role_id.clone(), update_payload)
|
.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 {
|
let update_payload = RolesRequestUpdateDto {
|
||||||
name: Some("Updated Role Name".into()),
|
name: Some("Updated Role Name".into()),
|
||||||
permissions: None,
|
permissions: None,
|
||||||
|
overwrite: None,
|
||||||
};
|
};
|
||||||
let update_res = repo
|
let update_res = repo
|
||||||
.query_update_role(existing_id.clone(), update_payload)
|
.query_update_role(existing_id.clone(), update_payload)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use crate::{create_mock_app_state, create_test_user, RolesRepository};
|
use crate::{MetaRequestDto, UsersRepository};
|
||||||
use crate::{
|
use crate::{RolesRepository, create_mock_app_state, create_test_user};
|
||||||
MetaRequestDto, UsersActiveInactiveSchema, UsersRepository,
|
|
||||||
UsersSetNewPasswordSchema,
|
|
||||||
};
|
|
||||||
|
|
||||||
async fn get_role_id(state: &crate::AppState) -> String {
|
async fn get_role_id(state: &crate::AppState) -> String {
|
||||||
RolesRepository::new(state)
|
RolesRepository::new(state)
|
||||||
@@ -31,35 +28,6 @@ async fn test_create_and_get_user() {
|
|||||||
assert_eq!(fetched.unwrap().email, "testuser@example.com");
|
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]
|
#[tokio::test]
|
||||||
async fn test_query_user_list_with_pagination_and_filter() {
|
async fn test_query_user_list_with_pagination_and_filter() {
|
||||||
let app_state = create_mock_app_state().await;
|
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);
|
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]
|
#[tokio::test]
|
||||||
async fn test_query_delete_user() {
|
async fn test_query_delete_user() {
|
||||||
let app_state = create_mock_app_state().await;
|
let app_state = create_mock_app_state().await;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
pub use imphnen_entities::*;
|
pub use imphnen_entities::*;
|
||||||
pub use imphnen_iam::*;
|
pub use imphnen_iam::*;
|
||||||
pub use imphnen_utils::*;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod iam;
|
pub mod iam;
|
||||||
|
|||||||
Reference in New Issue
Block a user