Refactor and enhance SurrealDB integration and resource management
- Updated `lib.rs` to selectively expose specific entities and services for better clarity. - Improved SurrealDB client initialization with detailed logging in `surrealdb/mod.rs`. - Enhanced resource definitions in `resource.rs` with additional utility methods for better resource management. - Refactored user data retrieval logic in `auth_middleware/mod.rs` for improved readability and efficiency. - Cleaned up middleware exports in `lib.rs` for clearer API surface. - Added detailed comments and documentation throughout the SurrealDB module for better maintainability. - Updated tests to ensure compatibility with new changes and improved structure. - Introduced new permissions module structure in `imphnen-utils` for future enhancements.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use imphnen_iam::TeamsSchema;
|
use imphnen_iam::v1::teams::TeamsSchema;
|
||||||
use imphnen_utils::get_iso_date;
|
use imphnen_utils::get_iso_date;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use surrealdb::{opt::auth::Root, sql::Thing};
|
use surrealdb::{opt::auth::Root, sql::Thing};
|
||||||
|
|||||||
@@ -1,2 +1,9 @@
|
|||||||
pub mod v1;
|
pub mod v1;
|
||||||
pub use v1::*;
|
|
||||||
|
pub use v1::landing;
|
||||||
|
pub use v1::landing::events;
|
||||||
|
pub use v1::landing::testimonials;
|
||||||
|
pub use v1::landing::events::events_public_routes;
|
||||||
|
pub use v1::landing::events::events_protected_routes;
|
||||||
|
pub use v1::landing::testimonials::testimonials_public_routes;
|
||||||
|
pub use v1::landing::testimonials::testimonials_protected_routes;
|
||||||
|
|||||||
@@ -9,36 +9,30 @@ pub mod events_repository;
|
|||||||
pub mod events_schema;
|
pub mod events_schema;
|
||||||
pub mod events_service;
|
pub mod events_service;
|
||||||
|
|
||||||
pub use events_controller::*;
|
// Export only the necessary public items
|
||||||
pub use events_dto::*;
|
pub use events_dto::{
|
||||||
pub use events_repository::*;
|
EventsCreateRequestDto,
|
||||||
pub use events_schema::*;
|
EventsUpdateRequestDto,
|
||||||
pub use events_service::*;
|
EventsListItemDto,
|
||||||
|
EventsDetailItemDto,
|
||||||
|
};
|
||||||
|
pub use events_controller::{
|
||||||
|
get_event_list,
|
||||||
|
get_event_by_id,
|
||||||
|
post_create_event,
|
||||||
|
patch_update_event,
|
||||||
|
delete_event,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn events_public_routes() -> Router {
|
pub fn events_public_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route(
|
.route("/cms/landing/events", get(get_event_list))
|
||||||
"/cms/landing/events",
|
.route("/cms/landing/events/detail/{id}", get(get_event_by_id))
|
||||||
get(events_controller::get_event_list),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/events/detail/{id}",
|
|
||||||
get(events_controller::get_event_by_id),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn events_protected_routes() -> Router {
|
pub fn events_protected_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route(
|
.route("/cms/landing/events/create", post(post_create_event))
|
||||||
"/cms/landing/events/create",
|
.route("/cms/landing/events/update/{id}", patch(patch_update_event))
|
||||||
post(events_controller::post_create_event),
|
.route("/cms/landing/events/delete/{id}", delete(delete_event))
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/events/update/{id}",
|
|
||||||
patch(events_controller::patch_update_event),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/events/delete/{id}",
|
|
||||||
delete(events_controller::delete_event),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod testimonials;
|
pub mod testimonials;
|
||||||
|
|
||||||
pub use events::*;
|
pub use events::events_public_routes;
|
||||||
pub use testimonials::*;
|
pub use events::events_protected_routes;
|
||||||
|
pub use testimonials::testimonials_public_routes;
|
||||||
|
pub use testimonials::testimonials_protected_routes;
|
||||||
|
|||||||
@@ -9,36 +9,30 @@ pub mod testimonials_repository;
|
|||||||
pub mod testimonials_schema;
|
pub mod testimonials_schema;
|
||||||
pub mod testimonials_service;
|
pub mod testimonials_service;
|
||||||
|
|
||||||
pub use testimonials_controller::*;
|
// Export only the necessary public items
|
||||||
pub use testimonials_dto::*;
|
pub use testimonials_dto::{
|
||||||
pub use testimonials_repository::*;
|
TestimonialsCreateRequestDto,
|
||||||
pub use testimonials_schema::*;
|
TestimonialsUpdateRequestDto,
|
||||||
pub use testimonials_service::*;
|
TestimonialsListItemDto,
|
||||||
|
TestimonialsDetailItemDto,
|
||||||
|
};
|
||||||
|
pub use testimonials_controller::{
|
||||||
|
get_testimonial_list,
|
||||||
|
get_testimonial_by_id,
|
||||||
|
post_create_testimonial,
|
||||||
|
patch_update_testimonial,
|
||||||
|
delete_testimonial,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn testimonials_public_routes() -> Router {
|
pub fn testimonials_public_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route(
|
.route("/cms/landing/testimonials", get(get_testimonial_list))
|
||||||
"/cms/landing/testimonials",
|
.route("/cms/landing/testimonials/detail/{id}", get(get_testimonial_by_id))
|
||||||
get(testimonials_controller::get_testimonial_list),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/testimonials/detail/{id}",
|
|
||||||
get(testimonials_controller::get_testimonial_by_id),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn testimonials_protected_routes() -> Router {
|
pub fn testimonials_protected_routes() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route(
|
.route("/cms/landing/testimonials/create", post(post_create_testimonial))
|
||||||
"/cms/landing/testimonials/create",
|
.route("/cms/landing/testimonials/update/{id}", patch(patch_update_testimonial))
|
||||||
post(testimonials_controller::post_create_testimonial),
|
.route("/cms/landing/testimonials/delete/{id}", delete(delete_testimonial))
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/testimonials/update/{id}",
|
|
||||||
patch(testimonials_controller::patch_update_testimonial),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/cms/landing/testimonials/delete/{id}",
|
|
||||||
delete(testimonials_controller::delete_testimonial),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
pub mod landing;
|
pub mod landing;
|
||||||
|
|
||||||
pub use landing::*;
|
pub use landing::events;
|
||||||
|
pub use landing::testimonials;
|
||||||
|
pub use landing::events::events_public_routes;
|
||||||
|
pub use landing::events::events_protected_routes;
|
||||||
|
pub use landing::testimonials::testimonials_public_routes;
|
||||||
|
pub use landing::testimonials::testimonials_protected_routes;
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
pub mod v1;
|
pub mod v1;
|
||||||
pub use v1::*;
|
|
||||||
|
// Explicitly export only what's needed from v1
|
||||||
|
pub use v1::dimentorin_router;
|
||||||
|
pub use v1::mentors::mentors_router;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ pub struct MentorUserRegisterRequestDto {
|
|||||||
message = "Password must have at least 8 characters"
|
message = "Password must have at least 8 characters"
|
||||||
))]
|
))]
|
||||||
#[validate(custom(
|
#[validate(custom(
|
||||||
function = "imphnen_iam::auth_dto::validate_password_complexity",
|
function = "imphnen_iam::v1::auth::auth_dto::validate_password_complexity",
|
||||||
message = "Password must include uppercase, lowercase, number, and special character"
|
message = "Password must include uppercase, lowercase, number, and special character"
|
||||||
))]
|
))]
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use anyhow::{Result, bail};
|
|||||||
use imphnen_iam::{get_id, make_thing};
|
use imphnen_iam::{get_id, make_thing};
|
||||||
use surrealdb::sql::Thing;
|
use surrealdb::sql::Thing;
|
||||||
|
|
||||||
use crate::v1::mentors::{MentorDetailWithUserDto, MentorInsertDto, MentorSchema};
|
use crate::v1::mentors::mentors_dto::MentorDetailWithUserDto;
|
||||||
|
use crate::v1::mentors::{MentorInsertDto, MentorSchema};
|
||||||
use imphnen_libs::{AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto};
|
use imphnen_libs::{AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto};
|
||||||
use imphnen_utils::{DetailQueryBuilder, QueryListBuilder, get_iso_date};
|
use imphnen_utils::{DetailQueryBuilder, QueryListBuilder, get_iso_date};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|||||||
@@ -9,11 +9,42 @@ pub mod mentors_repository;
|
|||||||
pub mod mentors_schema;
|
pub mod mentors_schema;
|
||||||
pub mod mentors_service;
|
pub mod mentors_service;
|
||||||
|
|
||||||
pub use mentors_controller::*;
|
// Explicitly export only public controller functions and key types
|
||||||
pub use mentors_dto::*;
|
pub use mentors_controller::{
|
||||||
pub use mentors_repository::*;
|
post_register_mentor,
|
||||||
pub use mentors_schema::*;
|
get_mentor_list,
|
||||||
pub use mentors_service::*;
|
get_mentor_by_id,
|
||||||
|
put_update_mentor,
|
||||||
|
delete_mentor,
|
||||||
|
put_verify_mentor,
|
||||||
|
get_mentor_me,
|
||||||
|
put_update_mentor_me,
|
||||||
|
put_update_mentor_no_id,
|
||||||
|
get_mentor_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export key DTO types used across the API
|
||||||
|
pub use mentors_dto::{
|
||||||
|
MentorListResponseDto,
|
||||||
|
MentorDetailResponseDto,
|
||||||
|
MentorRegisterResponseDto,
|
||||||
|
MentorUpdateRequestDto,
|
||||||
|
MentorUserRegisterRequestDto,
|
||||||
|
MentorVerifyRequestDto,
|
||||||
|
MentorDetailQueryDto,
|
||||||
|
ProfessionalProfile,
|
||||||
|
MentoringLogistics,
|
||||||
|
MentoringRate,
|
||||||
|
IdentityAndVerification,
|
||||||
|
MentorInsertDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export service and repository for internal use
|
||||||
|
pub use mentors_service::MentorsService;
|
||||||
|
pub use mentors_repository::MentorsRepository;
|
||||||
|
|
||||||
|
// Export schema types for database interactions
|
||||||
|
pub use mentors_schema::MentorSchema;
|
||||||
|
|
||||||
pub fn mentors_router() -> Router {
|
pub fn mentors_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|||||||
@@ -2,6 +2,16 @@ use axum::Router;
|
|||||||
|
|
||||||
pub mod mentors;
|
pub mod mentors;
|
||||||
|
|
||||||
|
/// Creates the main Dimentorin router with all version 1 endpoints
|
||||||
|
/// Routes:
|
||||||
|
/// - /mentors -> mentors::mentors_router()
|
||||||
pub fn dimentorin_router() -> Router {
|
pub fn dimentorin_router() -> Router {
|
||||||
Router::new().nest("/mentors", mentors::mentors_router())
|
Router::new()
|
||||||
|
.nest("/mentors", mentors::mentors_router())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly re-export key items for easier consumption
|
||||||
|
pub use mentors::mentors_router;
|
||||||
|
pub use mentors::MentorsService;
|
||||||
|
pub use mentors::MentorsRepository;
|
||||||
|
pub use mentors::MentorSchema;
|
||||||
|
|||||||
@@ -1 +1,14 @@
|
|||||||
|
/// Version 2 of the Dimentorin API - currently under development
|
||||||
|
/// This module will contain all version 2 endpoints following API versioning best practices
|
||||||
|
|
||||||
|
use axum::Router;
|
||||||
|
|
||||||
|
/// Placeholder for version 2 router
|
||||||
|
/// To be implemented when version 2 endpoints are ready
|
||||||
|
pub fn dimentorin_v2_router() -> Router {
|
||||||
|
Router::new()
|
||||||
|
// Version 2 endpoints will be added here following the same pattern as v1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-export the v1 router for backward compatibility
|
||||||
|
pub use crate::v1::dimentorin_router;
|
||||||
|
|||||||
@@ -2,7 +2,26 @@ pub mod common_dto;
|
|||||||
pub mod error_dto;
|
pub mod error_dto;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
pub mod permissions;
|
pub mod permissions;
|
||||||
pub use common_dto::*;
|
|
||||||
pub use error_dto::*;
|
// Re-export error type at root level for convenience
|
||||||
pub use users::*;
|
pub use error_dto::error::Error;
|
||||||
pub use permissions::*;
|
|
||||||
|
// Explicit common_dto exports
|
||||||
|
pub use common_dto::CountResult;
|
||||||
|
pub use common_dto::MessageResponseDto;
|
||||||
|
pub use common_dto::MetaRequestDto;
|
||||||
|
pub use common_dto::MetaResponseDto;
|
||||||
|
pub use common_dto::ResponseListSuccessDto;
|
||||||
|
pub use common_dto::ResponseSuccessDto;
|
||||||
|
|
||||||
|
// Explicit users exports
|
||||||
|
pub use users::EducationDto;
|
||||||
|
pub use users::ExperienceDto;
|
||||||
|
pub use users::RolesDetailItemDto;
|
||||||
|
pub use users::RolesDetailQueryDto;
|
||||||
|
pub use users::UsersDetailQueryDto;
|
||||||
|
|
||||||
|
// Explicit permissions exports
|
||||||
|
pub use permissions::PermissionsEnum;
|
||||||
|
pub use permissions::PermissionsItemDto;
|
||||||
|
pub use permissions::PermissionsQueryDto;
|
||||||
|
|||||||
@@ -1,6 +1,49 @@
|
|||||||
pub mod v1;
|
pub mod v1;
|
||||||
|
|
||||||
pub use imphnen_entities::*;
|
// Re-export core entity types used across the gacha system
|
||||||
pub use imphnen_libs::*;
|
pub use imphnen_entities::{
|
||||||
pub use imphnen_utils::*;
|
CountResult,
|
||||||
pub use v1::*;
|
Error,
|
||||||
|
ExperienceDto,
|
||||||
|
EducationDto,
|
||||||
|
MessageResponseDto,
|
||||||
|
MetaRequestDto,
|
||||||
|
MetaResponseDto,
|
||||||
|
PermissionsEnum,
|
||||||
|
PermissionsItemDto,
|
||||||
|
PermissionsQueryDto,
|
||||||
|
ResponseListSuccessDto,
|
||||||
|
ResponseSuccessDto,
|
||||||
|
UsersDetailQueryDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Explicitly import only what we need from libs and utils to avoid pollution
|
||||||
|
pub use imphnen_libs::{
|
||||||
|
AppState,
|
||||||
|
MinioService,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use imphnen_utils::{
|
||||||
|
bind_filter,
|
||||||
|
csrf_token,
|
||||||
|
extract_email,
|
||||||
|
generate_date,
|
||||||
|
generate_otp,
|
||||||
|
get_id,
|
||||||
|
logger,
|
||||||
|
make_thing,
|
||||||
|
mock_test,
|
||||||
|
query_builder,
|
||||||
|
query_list,
|
||||||
|
response_format,
|
||||||
|
serde_helpers,
|
||||||
|
validator,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Re-export public v1 API
|
||||||
|
pub use v1::{
|
||||||
|
gacha_claim_router,
|
||||||
|
gacha_item_router,
|
||||||
|
gacha_roll_router,
|
||||||
|
gacha_router,
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use axum::http::HeaderMap;
|
|||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::{Json, extract::Path};
|
use axum::{Json, extract::Path};
|
||||||
use imphnen_iam::{PermissionsEnum, permissions_guard};
|
use imphnen_iam::{PermissionsEnum, permissions_guard};
|
||||||
use imphnen_libs::{AppState, MessageResponseDto, ResponseSuccessDto};
|
use crate::AppState;
|
||||||
|
use imphnen_entities::{MessageResponseDto, ResponseSuccessDto};
|
||||||
use super::{GachaClaimItemDto, GachaClaimRequestDto, GachaClaimService};
|
use crate::v1::gacha_claims::{GachaClaimItemDto, GachaClaimRequestDto, GachaClaimService};
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::{GachaItemDto, GachaItemSchema};
|
use crate::v1::gacha_items::GachaItemDto;
|
||||||
|
use crate::v1::gacha_items::gacha_items_schema::GachaItemSchema;
|
||||||
use imphnen_iam::{UsersDetailItemDto, UsersDetailQueryDto};
|
use imphnen_iam::{UsersDetailItemDto, UsersDetailQueryDto};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::sql::Thing;
|
use surrealdb::sql::Thing;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use super::{GachaClaimQueryDto, GachaClaimSchema};
|
use crate::v1::gacha_claims::gacha_claims_dto::GachaClaimQueryDto;
|
||||||
use crate::{AppState, ResourceEnum};
|
use crate::v1::gacha_claims::gacha_claims_schema::GachaClaimSchema;
|
||||||
|
use crate::AppState;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use imphnen_iam::DetailQueryBuilder;
|
use imphnen_iam::DetailQueryBuilder;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::{GachaRollQueryDto, ResourceEnum, make_thing};
|
use crate::v1::gacha_rolls::gacha_rolls_dto::GachaRollQueryDto;
|
||||||
|
use crate::{make_thing};
|
||||||
use imphnen_iam::get_iso_date;
|
use imphnen_iam::get_iso_date;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::{Uuid, sql::Thing};
|
use surrealdb::{Uuid, sql::Thing};
|
||||||
|
|
||||||
use super::GachaClaimRequestDto;
|
use crate::v1::gacha_claims::gacha_claims_dto::GachaClaimRequestDto;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct GachaClaimSchema {
|
pub struct GachaClaimSchema {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use crate::{
|
use crate::AppState;
|
||||||
AppState, GachaClaimItemDto, GachaClaimRepository, GachaClaimRequestDto,
|
use imphnen_entities::ResponseSuccessDto;
|
||||||
GachaClaimSchema, ResponseSuccessDto, common_response, success_response,
|
use imphnen_utils::{common_response, success_response, validate_request};
|
||||||
validate_request,
|
use crate::v1::gacha_claims::gacha_claims_dto::{GachaClaimItemDto, GachaClaimRequestDto};
|
||||||
};
|
use crate::v1::gacha_claims::gacha_claims_repository::GachaClaimRepository;
|
||||||
|
use crate::v1::gacha_claims::gacha_claims_schema::GachaClaimSchema;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod gacha_claims_controller;
|
pub mod gacha_claims_controller;
|
||||||
@@ -9,14 +9,14 @@ pub mod gacha_claims_repository;
|
|||||||
pub mod gacha_claims_schema;
|
pub mod gacha_claims_schema;
|
||||||
pub mod gacha_claims_service;
|
pub mod gacha_claims_service;
|
||||||
|
|
||||||
pub use gacha_claims_controller::*;
|
// Export only public API functions
|
||||||
pub use gacha_claims_dto::*;
|
pub use gacha_claims_controller::{post_create_gacha_claim, get_detail_gacha_claim};
|
||||||
pub use gacha_claims_repository::*;
|
pub use gacha_claims_dto::{GachaClaimItemDto, GachaClaimRequestDto};
|
||||||
pub use gacha_claims_schema::*;
|
pub use gacha_claims_service::GachaClaimService;
|
||||||
pub use gacha_claims_service::*;
|
|
||||||
|
|
||||||
|
/// Creates router for gacha claims endpoints
|
||||||
pub fn gacha_claim_router() -> Router {
|
pub fn gacha_claim_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/create", post(post_create_gacha_claim))
|
.route("/create", post(post_create_gacha_claim))
|
||||||
.route("/detail/{id}", get(get_detail_gacha_claim))
|
.route("/detail/{id}", get(get_detail_gacha_claim))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use super::{GachaCreditRequestDto, GachaCreditSchema};
|
use crate::v1::gacha_credits::gacha_credits_dto::GachaCreditRequestDto;
|
||||||
use crate::{AppState, ResourceEnum};
|
use crate::v1::gacha_credits::gacha_credits_schema::GachaCreditSchema;
|
||||||
|
use crate::AppState;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use imphnen_iam::make_thing;
|
use imphnen_iam::make_thing;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|||||||
@@ -2,6 +2,5 @@ pub mod gacha_credits_dto;
|
|||||||
pub mod gacha_credits_repository;
|
pub mod gacha_credits_repository;
|
||||||
pub mod gacha_credits_schema;
|
pub mod gacha_credits_schema;
|
||||||
|
|
||||||
pub use gacha_credits_dto::*;
|
// Export only public types and functions
|
||||||
pub use gacha_credits_repository::*;
|
pub use gacha_credits_dto::GachaCreditRequestDto;
|
||||||
pub use gacha_credits_schema::*;
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto};
|
||||||
AppState, GachaItemDto, GachaItemRequestDto, GachaItemUpdateRequestDto, GachaItemService, MessageResponseDto,
|
use imphnen_entities::MessageResponseDto;
|
||||||
MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto,
|
use crate::v1::gacha_items::GachaItemDto;
|
||||||
};
|
use crate::v1::gacha_items::gacha_items_dto::{GachaItemRequestDto, GachaItemUpdateRequestDto};
|
||||||
|
use crate::v1::gacha_items::gacha_items_service::GachaItemService;
|
||||||
use axum::{
|
use axum::{
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
extract::{Path, Query},
|
extract::{Path, Query},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::GachaItemSchema;
|
use crate::v1::gacha_items::gacha_items_schema::GachaItemSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use super::GachaItemSchema;
|
use crate::v1::gacha_items::gacha_items_schema::GachaItemSchema;
|
||||||
use crate::{
|
use crate::{AppState, MetaRequestDto, ResponseListSuccessDto, get_id, make_thing};
|
||||||
AppState, GachaItemDto, MetaRequestDto, ResourceEnum, ResponseListSuccessDto,
|
use crate::v1::gacha_items::GachaItemDto;
|
||||||
get_id, make_thing,
|
use imphnen_libs::ResourceEnum;
|
||||||
};
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use imphnen_iam::QueryListBuilder;
|
use imphnen_iam::QueryListBuilder;
|
||||||
use imphnen_utils::get_iso_date;
|
use imphnen_utils::get_iso_date;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use crate::{ResourceEnum, make_thing};
|
use crate::make_thing;
|
||||||
use imphnen_iam::get_iso_date;
|
use imphnen_iam::get_iso_date;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::{Uuid, sql::Thing};
|
use surrealdb::{Uuid, sql::Thing};
|
||||||
|
|
||||||
use super::GachaItemRequestDto;
|
use crate::v1::gacha_items::gacha_items_dto::GachaItemRequestDto;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct GachaItemSchema {
|
pub struct GachaItemSchema {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::{
|
use crate::AppState;
|
||||||
AppState, GachaItemDto, GachaItemRepository, GachaItemRequestDto, GachaItemUpdateRequestDto, GachaItemSchema,
|
use imphnen_entities::{MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto};
|
||||||
MetaRequestDto, ResourceEnum, ResponseListSuccessDto, ResponseSuccessDto,
|
use imphnen_utils::{common_response, make_thing, success_list_response, success_response, validate_request};
|
||||||
common_response, make_thing, success_list_response, success_response,
|
use crate::v1::gacha_items::GachaItemDto;
|
||||||
validate_request,
|
use crate::v1::gacha_items::gacha_items_dto::{GachaItemRequestDto, GachaItemUpdateRequestDto};
|
||||||
};
|
use crate::v1::gacha_items::gacha_items_repository::GachaItemRepository;
|
||||||
|
use crate::v1::gacha_items::gacha_items_schema::GachaItemSchema;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
use imphnen_utils::get_iso_date;
|
use imphnen_utils::get_iso_date;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
routing::{delete, get, post, put},
|
routing::{delete, get, post, put},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod gacha_items_controller;
|
pub mod gacha_items_controller;
|
||||||
@@ -9,17 +9,22 @@ pub mod gacha_items_repository;
|
|||||||
pub mod gacha_items_schema;
|
pub mod gacha_items_schema;
|
||||||
pub mod gacha_items_service;
|
pub mod gacha_items_service;
|
||||||
|
|
||||||
pub use gacha_items_controller::*;
|
// Export only public API functions and types
|
||||||
pub use gacha_items_dto::*;
|
pub use gacha_items_controller::{
|
||||||
pub use gacha_items_repository::*;
|
get_gacha_item_list,
|
||||||
pub use gacha_items_schema::*;
|
post_create_gacha_item,
|
||||||
pub use gacha_items_service::*;
|
get_gacha_item_by_id,
|
||||||
|
put_update_gacha_item,
|
||||||
|
delete_gacha_item,
|
||||||
|
};
|
||||||
|
pub use gacha_items_dto::GachaItemDto;
|
||||||
|
|
||||||
|
/// Creates router for gacha items endpoints
|
||||||
pub fn gacha_item_router() -> Router {
|
pub fn gacha_item_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(get_gacha_item_list))
|
.route("/", get(get_gacha_item_list))
|
||||||
.route("/create", post(post_create_gacha_item))
|
.route("/create", post(post_create_gacha_item))
|
||||||
.route("/detail/{id}", get(get_gacha_item_by_id))
|
.route("/detail/{id}", get(get_gacha_item_by_id))
|
||||||
.route("/update/{id}", put(put_update_gacha_item))
|
.route("/update/{id}", put(put_update_gacha_item))
|
||||||
.route("/delete/{id}", delete(delete_gacha_item))
|
.route("/delete/{id}", delete(delete_gacha_item))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::AppState;
|
||||||
AppState, GachaRollItemDto, GachaRollRequestDto, GachaRollService,
|
use imphnen_entities::{MessageResponseDto, ResponseSuccessDto};
|
||||||
MessageResponseDto, ResponseSuccessDto,
|
use crate::v1::gacha_rolls::gacha_rolls_dto::{GachaRollItemDto, GachaRollRequestDto};
|
||||||
};
|
use crate::v1::gacha_rolls::gacha_rolls_service::GachaRollService;
|
||||||
use axum::{
|
use axum::{
|
||||||
Extension, Json, extract::Path, http::HeaderMap, response::IntoResponse,
|
Extension, Json, extract::Path, http::HeaderMap, response::IntoResponse,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::{GachaItemDto, GachaItemSchema};
|
use crate::v1::gacha_items::GachaItemDto;
|
||||||
|
use crate::v1::gacha_items::gacha_items_schema::GachaItemSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::sql::Thing;
|
use surrealdb::sql::Thing;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use super::GachaRollQueryDto;
|
use crate::v1::gacha_rolls::gacha_rolls_dto::GachaRollQueryDto;
|
||||||
use super::GachaRollSchema;
|
use crate::v1::gacha_rolls::gacha_rolls_schema::GachaRollSchema;
|
||||||
use crate::{AppState, DetailQueryBuilder, ResourceEnum, get_id, make_thing};
|
use crate::AppState;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
|
use imphnen_utils::DetailQueryBuilder;
|
||||||
|
use crate::{get_id, make_thing};
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use crate::{ResourceEnum, make_thing};
|
use crate::make_thing;
|
||||||
use imphnen_iam::get_iso_date;
|
use imphnen_iam::get_iso_date;
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use surrealdb::{Uuid, sql::Thing};
|
use surrealdb::{Uuid, sql::Thing};
|
||||||
|
|
||||||
use super::GachaRollRequestDto;
|
use crate::v1::gacha_rolls::gacha_rolls_dto::GachaRollRequestDto;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct GachaRollSchema {
|
pub struct GachaRollSchema {
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
use crate::{
|
use crate::AppState;
|
||||||
AppState, GachaClaimRepository, GachaClaimSchema, GachaRollItemDto,
|
use imphnen_entities::ResponseSuccessDto;
|
||||||
GachaRollRepository, GachaRollRequestDto, GachaRollSchema, ResponseSuccessDto,
|
use imphnen_utils::{common_response, success_response, validate_request};
|
||||||
common_response, success_response, validate_request,
|
use crate::v1::gacha_claims::gacha_claims_repository::GachaClaimRepository;
|
||||||
};
|
use crate::v1::gacha_claims::gacha_claims_schema::GachaClaimSchema;
|
||||||
|
use crate::v1::gacha_rolls::gacha_rolls_dto::{GachaRollItemDto, GachaRollRequestDto};
|
||||||
|
use crate::v1::gacha_rolls::gacha_rolls_repository::GachaRollRepository;
|
||||||
|
use crate::v1::gacha_rolls::gacha_rolls_schema::GachaRollSchema;
|
||||||
use axum::http::{HeaderMap, StatusCode};
|
use axum::http::{HeaderMap, StatusCode};
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
use imphnen_iam::{UsersRepository, extract_email};
|
use imphnen_iam::UsersRepository;
|
||||||
|
use imphnen_utils::extract_email;
|
||||||
|
|
||||||
pub struct GachaRollService;
|
pub struct GachaRollService;
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
|
use axum::{
|
||||||
|
Router,
|
||||||
|
routing::{get, post},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod gacha_rolls_controller;
|
pub mod gacha_rolls_controller;
|
||||||
pub mod gacha_rolls_dto;
|
pub mod gacha_rolls_dto;
|
||||||
pub mod gacha_rolls_repository;
|
pub mod gacha_rolls_repository;
|
||||||
pub mod gacha_rolls_schema;
|
pub mod gacha_rolls_schema;
|
||||||
pub mod gacha_rolls_service;
|
pub mod gacha_rolls_service;
|
||||||
|
|
||||||
use axum::{
|
// Export only public API functions and types
|
||||||
Router,
|
pub use gacha_rolls_controller::{
|
||||||
routing::{get, post},
|
post_create_gacha_roll,
|
||||||
|
post_execute_gacha_roll,
|
||||||
|
get_detail_gacha_roll,
|
||||||
};
|
};
|
||||||
pub use gacha_rolls_controller::*;
|
pub use gacha_rolls_dto::GachaRollItemDto;
|
||||||
pub use gacha_rolls_dto::*;
|
|
||||||
pub use gacha_rolls_repository::*;
|
|
||||||
pub use gacha_rolls_schema::*;
|
|
||||||
pub use gacha_rolls_service::*;
|
|
||||||
|
|
||||||
|
/// Creates router for gacha rolls endpoints
|
||||||
pub fn gacha_roll_router() -> Router {
|
pub fn gacha_roll_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/create", post(post_create_gacha_roll))
|
.route("/create", post(post_create_gacha_roll))
|
||||||
.route("/execute", post(post_execute_gacha_roll))
|
.route("/execute", post(post_execute_gacha_roll))
|
||||||
.route("/detail/{id}", get(get_detail_gacha_roll))
|
.route("/detail/{id}", get(get_detail_gacha_roll))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,16 @@ pub mod gacha_credits;
|
|||||||
pub mod gacha_items;
|
pub mod gacha_items;
|
||||||
pub mod gacha_rolls;
|
pub mod gacha_rolls;
|
||||||
|
|
||||||
pub use gacha_claims::*;
|
// Export only public router functions to avoid namespace pollution
|
||||||
pub use gacha_credits::*;
|
pub use gacha_claims::gacha_claim_router;
|
||||||
pub use gacha_items::*;
|
pub use gacha_credits::*; // gacha_credits doesn't have router functions
|
||||||
pub use gacha_rolls::*;
|
pub use gacha_items::gacha_item_router;
|
||||||
|
pub use gacha_rolls::gacha_roll_router;
|
||||||
|
|
||||||
|
/// Creates the main gacha router with all version 1 endpoints
|
||||||
pub fn gacha_router() -> Router {
|
pub fn gacha_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest("/gacha/claims", gacha_claim_router())
|
.nest("/claims", gacha_claim_router())
|
||||||
.nest("/gacha/items", gacha_item_router())
|
.nest("/items", gacha_item_router())
|
||||||
.nest("/gacha/rolls", gacha_roll_router())
|
.nest("/rolls", gacha_roll_router())
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-33
@@ -1,11 +1,9 @@
|
|||||||
use imphnen_cms::{
|
use imphnen_cms::v1::landing::events::events_controller;
|
||||||
events_controller,
|
use imphnen_cms::v1::landing::events::events_dto::{EventsDetailItemDto, EventsListItemDto};
|
||||||
events_dto::{EventsDetailItemDto, EventsListItemDto},
|
use imphnen_cms::v1::landing::testimonials::testimonials_controller;
|
||||||
testimonials_controller,
|
use imphnen_cms::v1::landing::testimonials::testimonials_dto::{
|
||||||
testimonials_dto::{
|
TestimonialsCreateRequestDto, TestimonialsDetailItemDto,
|
||||||
TestimonialsCreateRequestDto, TestimonialsDetailItemDto,
|
TestimonialsListItemDto, TestimonialsUpdateRequestDto,
|
||||||
TestimonialsListItemDto, TestimonialsUpdateRequestDto,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use imphnen_dimentorin::v1::mentors::{
|
use imphnen_dimentorin::v1::mentors::{
|
||||||
mentors_controller,
|
mentors_controller,
|
||||||
@@ -16,21 +14,20 @@ use imphnen_dimentorin::v1::mentors::{
|
|||||||
MentoringLogistics, MentoringRate, ProfessionalProfile,
|
MentoringLogistics, MentoringRate, ProfessionalProfile,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use imphnen_gacha::{
|
use imphnen_gacha::v1::gacha_claims::{gacha_claims_controller, GachaClaimItemDto, GachaClaimRequestDto};
|
||||||
GachaClaimItemDto, GachaClaimRequestDto, GachaItemDto, GachaItemRequestDto,
|
use imphnen_gacha::v1::gacha_items::{gacha_items_controller, GachaItemDto};
|
||||||
GachaRollItemDto, GachaRollRequestDto, gacha_claims, gacha_items, gacha_rolls,
|
use imphnen_gacha::v1::gacha_items::gacha_items_dto::GachaItemRequestDto;
|
||||||
};
|
use imphnen_gacha::v1::gacha_rolls::{gacha_rolls_controller, GachaRollItemDto};
|
||||||
|
use imphnen_gacha::v1::gacha_rolls::gacha_rolls_dto::GachaRollRequestDto;
|
||||||
use imphnen_entities::{PermissionsItemDto, RolesDetailItemDto};
|
use imphnen_entities::{PermissionsItemDto, RolesDetailItemDto};
|
||||||
use imphnen_iam::{
|
use imphnen_entities::{MessageResponseDto, MetaRequestDto, MetaResponseDto, ResponseListSuccessDto, ResponseSuccessDto};
|
||||||
AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto,
|
use imphnen_iam::v1::auth::auth_dto::{AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto, TokenDto};
|
||||||
AuthRefreshTokenRequestDto, AuthResendOtpRequestDto, AuthVerifyEmailRequestDto,
|
use imphnen_iam::v1::permissions::permissions_dto::PermissionsRequestDto;
|
||||||
MessageResponseDto, MetaRequestDto, MetaResponseDto, PermissionsRequestDto,
|
use imphnen_iam::v1::roles::RolesListItemDto;
|
||||||
ResponseListSuccessDto, ResponseSuccessDto, RolesListItemDto, RolesRequestCreateDto,
|
use imphnen_iam::v1::roles::roles_dto::{RolesRequestCreateDto, RolesRequestUpdateDto};
|
||||||
RolesRequestUpdateDto, TokenDto, UsersCreateRequestDto, UsersDetailItemDto,
|
use imphnen_iam::v1::users::UsersDetailItemDto;
|
||||||
UsersListItemDto, UsersUpdateRequestDto, TeamsCreateRequestDto, TeamsUpdateRequestDto,
|
use imphnen_iam::v1::users::users_dto::{UsersCreateRequestDto, UsersListItemDto, UsersUpdateRequestDto};
|
||||||
TeamInviteRequestDto, TeamAcceptInvitationRequestDto, TeamsDetailItemDto,
|
use imphnen_iam::v1::teams::teams_dto::{TeamsCreateRequestDto, TeamsUpdateRequestDto, TeamInviteRequestDto, TeamAcceptInvitationRequestDto, TeamsDetailItemDto, TeamsListItemDto, TeamMemberDto, TeamInvitationDto, TeamsSearchQueryDto};
|
||||||
TeamsListItemDto, TeamMemberDto, TeamInvitationDto, TeamsSearchQueryDto,
|
|
||||||
};
|
|
||||||
use imphnen_iam::v1::{auth, permissions, roles, users, teams};
|
use imphnen_iam::v1::{auth, permissions, roles, users, teams};
|
||||||
use imphnen_iam::v1::users::users_controller::FileUploadSchema;
|
use imphnen_iam::v1::users::users_controller::FileUploadSchema;
|
||||||
use utoipa::{
|
use utoipa::{
|
||||||
@@ -78,16 +75,16 @@ use utoipa::{
|
|||||||
teams::teams_controller::get_public_team_search,
|
teams::teams_controller::get_public_team_search,
|
||||||
teams::teams_controller::get_team_members,
|
teams::teams_controller::get_team_members,
|
||||||
teams::teams_controller::post_leave_team,
|
teams::teams_controller::post_leave_team,
|
||||||
gacha_claims::get_detail_gacha_claim,
|
gacha_claims_controller::get_detail_gacha_claim,
|
||||||
gacha_claims::post_create_gacha_claim,
|
gacha_claims_controller::post_create_gacha_claim,
|
||||||
gacha_items::get_gacha_item_list,
|
gacha_items_controller::get_gacha_item_list,
|
||||||
gacha_items::get_gacha_item_by_id,
|
gacha_items_controller::get_gacha_item_by_id,
|
||||||
gacha_items::post_create_gacha_item,
|
gacha_items_controller::post_create_gacha_item,
|
||||||
gacha_items::put_update_gacha_item,
|
gacha_items_controller::put_update_gacha_item,
|
||||||
gacha_items::delete_gacha_item,
|
gacha_items_controller::delete_gacha_item,
|
||||||
gacha_rolls::get_detail_gacha_roll,
|
gacha_rolls_controller::get_detail_gacha_roll,
|
||||||
gacha_rolls::post_create_gacha_roll,
|
gacha_rolls_controller::post_create_gacha_roll,
|
||||||
gacha_rolls::post_execute_gacha_roll,
|
gacha_rolls_controller::post_execute_gacha_roll,
|
||||||
events_controller::get_event_list,
|
events_controller::get_event_list,
|
||||||
events_controller::get_event_by_id,
|
events_controller::get_event_by_id,
|
||||||
events_controller::post_create_event,
|
events_controller::post_create_event,
|
||||||
@@ -209,7 +206,7 @@ use utoipa::{
|
|||||||
|
|
||||||
pub struct ApiDoc;
|
pub struct ApiDoc;
|
||||||
|
|
||||||
struct SecurityAddon;
|
pub struct SecurityAddon;
|
||||||
|
|
||||||
impl Modify for SecurityAddon {
|
impl Modify for SecurityAddon {
|
||||||
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
||||||
|
|||||||
+42
-33
@@ -1,51 +1,60 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
Extension, Router, middleware::from_fn, response::Redirect, routing::get,
|
Extension,
|
||||||
|
Router,
|
||||||
|
middleware::from_fn,
|
||||||
|
response::Redirect,
|
||||||
|
routing::get,
|
||||||
};
|
};
|
||||||
use imphnen_cms::{
|
use imphnen_cms::{
|
||||||
events_protected_routes, events_public_routes, testimonials_protected_routes,
|
events_protected_routes,
|
||||||
testimonials_public_routes,
|
events_public_routes,
|
||||||
|
testimonials_protected_routes,
|
||||||
|
testimonials_public_routes,
|
||||||
};
|
};
|
||||||
use imphnen_dimentorin::dimentorin_router;
|
use imphnen_dimentorin::dimentorin_router;
|
||||||
use imphnen_libs::{AppState, SurrealMemClient, SurrealWsClient};
|
|
||||||
use imphnen_gacha::gacha_router;
|
use imphnen_gacha::gacha_router;
|
||||||
use imphnen_iam::{iam_protected_routes, iam_public_routes, v1::users::users_service::UsersService, v1::auth::auth_repository::AuthRepoImpl};
|
use imphnen_iam::{
|
||||||
|
iam_protected_routes,
|
||||||
|
iam_public_routes,
|
||||||
|
v1::users::users_service::UsersService,
|
||||||
|
v1::auth::auth_repository::AuthRepoImpl,
|
||||||
|
};
|
||||||
|
use imphnen_libs::{AppState, SurrealMemClient, SurrealWsClient};
|
||||||
use imphnen_middleware::{auth_middleware, cors_middleware};
|
use imphnen_middleware::{auth_middleware, cors_middleware};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use utoipa_swagger_ui::SwaggerUi;
|
use utoipa_swagger_ui::SwaggerUi;
|
||||||
|
|
||||||
pub mod docs;
|
pub mod docs;
|
||||||
pub use docs::*;
|
pub use docs::{ApiDoc, SecurityAddon, docs_router};
|
||||||
|
|
||||||
pub async fn gateway_service(
|
pub async fn gateway_service(
|
||||||
surrealdb_ws: SurrealWsClient,
|
surrealdb_ws: SurrealWsClient,
|
||||||
surrealdb_mem: SurrealMemClient,
|
surrealdb_mem: SurrealMemClient,
|
||||||
) -> Router {
|
) -> Router {
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
surrealdb_ws,
|
surrealdb_ws,
|
||||||
surrealdb_mem: surrealdb_mem.clone(),
|
surrealdb_mem: surrealdb_mem.clone(),
|
||||||
user_lookup_service: Arc::new(UsersService),
|
user_lookup_service: Arc::new(UsersService),
|
||||||
auth_repository: Arc::new(AuthRepoImpl { db: surrealdb_mem }),
|
auth_repository: Arc::new(AuthRepoImpl { db: surrealdb_mem }),
|
||||||
};
|
};
|
||||||
|
|
||||||
let public_routes = Router::new()
|
let public_routes = Router::new()
|
||||||
.merge(iam_public_routes())
|
.merge(iam_public_routes())
|
||||||
.merge(testimonials_public_routes())
|
.merge(testimonials_public_routes())
|
||||||
.merge(events_public_routes());
|
.merge(events_public_routes());
|
||||||
|
|
||||||
let protected_routes = Router::new()
|
let protected_routes = Router::new()
|
||||||
.merge(iam_protected_routes())
|
.merge(iam_protected_routes())
|
||||||
.merge(events_protected_routes())
|
.merge(events_protected_routes())
|
||||||
.merge(testimonials_protected_routes())
|
.merge(testimonials_protected_routes())
|
||||||
.merge(dimentorin_router())
|
.merge(dimentorin_router())
|
||||||
.merge(gacha_router())
|
.merge(gacha_router())
|
||||||
.layer(from_fn(auth_middleware));
|
.layer(from_fn(auth_middleware));
|
||||||
|
|
||||||
let routes = public_routes.merge(protected_routes);
|
Router::new()
|
||||||
|
.route("/", get(Redirect::to("/docs")))
|
||||||
Router::new()
|
.nest("/v1", public_routes.merge(protected_routes))
|
||||||
.route("/", get(Redirect::to("/docs")))
|
.merge(SwaggerUi::new("/docs").url("/openapi.json", docs_router()))
|
||||||
.nest("/v1", routes)
|
.layer(cors_middleware())
|
||||||
.merge(SwaggerUi::new("/docs").url("/openapi.json", docs_router()))
|
.layer(Extension(state))
|
||||||
.layer(cors_middleware())
|
|
||||||
.layer(Extension(state))
|
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-4
@@ -1,6 +1,93 @@
|
|||||||
pub mod v1;
|
pub mod v1;
|
||||||
|
|
||||||
pub use imphnen_entities::*;
|
// Re-export core entity types used throughout the IAM module
|
||||||
pub use imphnen_libs::*;
|
pub use imphnen_entities::{
|
||||||
pub use imphnen_utils::*;
|
MessageResponseDto,
|
||||||
pub use v1::*;
|
MetaRequestDto,
|
||||||
|
MetaResponseDto,
|
||||||
|
ResponseSuccessDto,
|
||||||
|
ResponseListSuccessDto,
|
||||||
|
CountResult,
|
||||||
|
Error,
|
||||||
|
ExperienceDto,
|
||||||
|
EducationDto,
|
||||||
|
UsersDetailQueryDto,
|
||||||
|
PermissionsEnum,
|
||||||
|
PermissionsItemDto,
|
||||||
|
PermissionsQueryDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Explicitly export only the imphnen_libs types actually used in IAM
|
||||||
|
pub use imphnen_libs::{
|
||||||
|
AppState,
|
||||||
|
ResourceEnum,
|
||||||
|
decode_access_token,
|
||||||
|
decode_refresh_token,
|
||||||
|
encode_access_token,
|
||||||
|
encode_refresh_token,
|
||||||
|
encode_reset_password_token,
|
||||||
|
hash_password,
|
||||||
|
send_email,
|
||||||
|
verify_password,
|
||||||
|
Env,
|
||||||
|
SurrealWsClient,
|
||||||
|
SurrealMemClient,
|
||||||
|
UserLookupService,
|
||||||
|
AuthRepositoryTrait,
|
||||||
|
jsonwebtoken::Claims,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Explicitly export only the imphnen_utils types actually used in IAM
|
||||||
|
pub use imphnen_utils::{
|
||||||
|
make_thing,
|
||||||
|
make_thing_from_enum,
|
||||||
|
get_id,
|
||||||
|
get_iso_date,
|
||||||
|
extract_id,
|
||||||
|
build_multi_thing_condition,
|
||||||
|
execute_safe_update_query,
|
||||||
|
DetailQueryBuilder,
|
||||||
|
QueryListBuilder,
|
||||||
|
success_response,
|
||||||
|
success_list_response,
|
||||||
|
common_response,
|
||||||
|
validate_request,
|
||||||
|
generate_oauth_csrf_token,
|
||||||
|
validate_oauth_csrf_token,
|
||||||
|
validate_csrf_token,
|
||||||
|
extract_email_token_async,
|
||||||
|
OtpManager,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export the main router functions and types from v1 module
|
||||||
|
pub use v1::{
|
||||||
|
iam_public_routes,
|
||||||
|
iam_protected_routes,
|
||||||
|
auth_router,
|
||||||
|
users_router,
|
||||||
|
roles_router,
|
||||||
|
permissions_router,
|
||||||
|
teams_router,
|
||||||
|
permissions_guard,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export IAM-specific types
|
||||||
|
pub use v1::auth::{
|
||||||
|
AuthRepository, AuthOtpSchema,
|
||||||
|
AuthLoginRequestDto, AuthLoginResponsetDto, AuthRegisterRequestDto,
|
||||||
|
AuthResendOtpRequestDto, AuthVerifyEmailRequestDto,
|
||||||
|
AuthNewPasswordRequestDto, AuthRefreshTokenRequestDto,
|
||||||
|
TokenDto, UserCacheSchema,
|
||||||
|
};
|
||||||
|
pub use v1::permissions::{PermissionsRepository, PermissionsSchema};
|
||||||
|
pub use v1::roles::{RolesRepository, RolesSchema, RolesEnum, RolesDetailQueryDto, RolesRequestCreateDto, RolesRequestUpdateDto, RolesDetailItemDto};
|
||||||
|
pub use v1::teams::{
|
||||||
|
TeamsRepository, TeamsSchema, TeamsCreateRequestDto, TeamsUpdateRequestDto,
|
||||||
|
TeamInviteRequestDto, TeamMemberDto, AdminTeamsListItemDto,
|
||||||
|
AdminTeamsDetailItemDto, TeamsDetailItemDto, TeamsListItemDto,
|
||||||
|
TeamAcceptInvitationRequestDto, TeamsSearchQueryDto, PublicTeamsListItemDto,
|
||||||
|
PublicTeamsDetailItemDto, TeamsDetailQueryDto, TeamsListQueryDto,
|
||||||
|
TeamMembersSchema, TeamInvitationsSchema, TeamMembersQueryDto,
|
||||||
|
TeamInvitationsQueryDto, MemberTeamsDetailItemDto,
|
||||||
|
};
|
||||||
|
pub use v1::users::{UsersRepository, UsersSchema, UsersDetailItemDto, UsersCreateRequestDto};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use super::{
|
|||||||
AuthLoginRequestDto, AuthRefreshTokenRequestDto, AuthRegisterRequestDto,
|
AuthLoginRequestDto, AuthRefreshTokenRequestDto, AuthRegisterRequestDto,
|
||||||
AuthResendOtpRequestDto, AuthVerifyEmailRequestDto,
|
AuthResendOtpRequestDto, AuthVerifyEmailRequestDto,
|
||||||
};
|
};
|
||||||
use crate::{AppState, v1::AuthLoginResponsetDto};
|
use crate::{AppState, v1::auth::AuthLoginResponsetDto};
|
||||||
use crate::{AuthNewPasswordRequestDto, MessageResponseDto, ResponseSuccessDto};
|
use crate::{AuthNewPasswordRequestDto, MessageResponseDto, ResponseSuccessDto};
|
||||||
use axum::{Extension, Json, response::IntoResponse};
|
use axum::{Extension, Json, response::IntoResponse};
|
||||||
use crate::v1::auth::auth_service::AuthServiceTrait;
|
use crate::v1::auth::auth_service::AuthServiceTrait;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use imphnen_utils as generate_otp;
|
||||||
|
use imphnen_libs::enviroment;
|
||||||
use super::{
|
use super::{
|
||||||
AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto,
|
AuthLoginRequestDto, AuthLoginResponsetDto, AuthNewPasswordRequestDto,
|
||||||
AuthRefreshTokenRequestDto, AuthRegisterRequestDto, AuthRepository,
|
AuthRefreshTokenRequestDto, AuthRegisterRequestDto, AuthRepository,
|
||||||
@@ -9,7 +11,7 @@ use crate::{
|
|||||||
AppState, ResourceEnum, ResponseSuccessDto, RolesEnum, RolesRepository,
|
AppState, ResourceEnum, ResponseSuccessDto, RolesEnum, RolesRepository,
|
||||||
UsersDetailItemDto, UsersRepository, UsersSchema, common_response,
|
UsersDetailItemDto, UsersRepository, UsersSchema, common_response,
|
||||||
decode_refresh_token, encode_access_token, encode_refresh_token,
|
decode_refresh_token, encode_access_token, encode_refresh_token,
|
||||||
encode_reset_password_token, extract_email_token_async, generate_otp, get_iso_date,
|
encode_reset_password_token, extract_email_token_async, 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,
|
verify_password,
|
||||||
};
|
};
|
||||||
@@ -475,7 +477,7 @@ impl AuthServiceTrait for AuthService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let env = &crate::enviroment::ENV;
|
let env = &enviroment::ENV;
|
||||||
let fe_url = env.fe_url.clone();
|
let fe_url = env.fe_url.clone();
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"You have requested a password reset. Please click the link below to continue: {fe_url}/auth/reset-password?token={token}"
|
"You have requested a password reset. Please click the link below to continue: {fe_url}/auth/reset-password?token={token}"
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
/// Google OAuth integration module
|
||||||
pub mod google_oauth_controller;
|
pub mod google_oauth_controller;
|
||||||
pub mod google_oauth_dto;
|
pub mod google_oauth_dto;
|
||||||
pub mod google_oauth_service;
|
pub mod google_oauth_service;
|
||||||
|
|
||||||
|
// Export only essential types and functions from Google OAuth submodules
|
||||||
|
pub use google_oauth_controller::GoogleOauthController;
|
||||||
@@ -7,20 +7,45 @@ pub mod auth_schema;
|
|||||||
pub mod auth_service;
|
pub mod auth_service;
|
||||||
pub mod google;
|
pub mod google;
|
||||||
|
|
||||||
pub use auth_dto::*;
|
// Export only the essential types and functions from each submodule
|
||||||
pub use auth_repository::*;
|
pub use auth_dto::{
|
||||||
pub use auth_schema::*;
|
AuthLoginRequestDto,
|
||||||
pub use auth_service::*;
|
AuthLoginResponsetDto,
|
||||||
|
AuthRegisterRequestDto,
|
||||||
|
AuthResendOtpRequestDto,
|
||||||
|
AuthVerifyEmailRequestDto,
|
||||||
|
AuthNewPasswordRequestDto,
|
||||||
|
AuthRefreshTokenRequestDto,
|
||||||
|
TokenDto,
|
||||||
|
UserCacheSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use auth_repository::AuthRepository;
|
||||||
|
pub use imphnen_libs::AuthRepositoryTrait;
|
||||||
|
pub use auth_schema::AuthOtpSchema;
|
||||||
|
pub use auth_service::AuthServiceTrait;
|
||||||
|
|
||||||
|
// Export controller functions that are used in routing
|
||||||
|
pub use auth_controller::{
|
||||||
|
post_login,
|
||||||
|
post_login_mentor,
|
||||||
|
post_register,
|
||||||
|
post_forgot_password,
|
||||||
|
post_new_password,
|
||||||
|
post_refresh_token,
|
||||||
|
post_resend_otp,
|
||||||
|
post_verify_email
|
||||||
|
};
|
||||||
|
|
||||||
pub fn auth_router() -> Router {
|
pub fn auth_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest("/google", google::google_oauth_controller::GoogleOauthController::new().get_routes())
|
.nest("/google", google::google_oauth_controller::GoogleOauthController::new().get_routes())
|
||||||
.route("/forgot", post(auth_controller::post_forgot_password))
|
.route("/forgot", post(post_forgot_password))
|
||||||
.route("/login", post(auth_controller::post_login))
|
.route("/login", post(post_login))
|
||||||
.route("/login-mentor", post(auth_controller::post_login_mentor))
|
.route("/login-mentor", post(post_login_mentor))
|
||||||
.route("/new-password", post(auth_controller::post_new_password))
|
.route("/new-password", post(post_new_password))
|
||||||
.route("/refresh", post(auth_controller::post_refresh_token))
|
.route("/refresh", post(post_refresh_token))
|
||||||
.route("/register", post(auth_controller::post_register))
|
.route("/register", post(post_register))
|
||||||
.route("/send-otp", post(auth_controller::post_resend_otp))
|
.route("/send-otp", post(post_resend_otp))
|
||||||
.route("/verify-email", post(auth_controller::post_verify_email))
|
.route("/verify-email", post(post_verify_email))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ pub mod roles;
|
|||||||
pub mod teams;
|
pub mod teams;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
|
||||||
pub use auth::*;
|
// Export only the essential router functions from each module
|
||||||
pub use permissions::*;
|
pub use auth::auth_router;
|
||||||
pub use roles::*;
|
pub use permissions::{permissions_router, permissions_dto, permissions_service, permissions_guard};
|
||||||
pub use teams::*;
|
pub use roles::{roles_router, roles_service};
|
||||||
pub use users::*;
|
pub use teams::teams_router;
|
||||||
|
pub use users::users_router;
|
||||||
|
|
||||||
|
// Main route constructors
|
||||||
pub fn iam_public_routes() -> Router {
|
pub fn iam_public_routes() -> Router {
|
||||||
Router::new().nest("/auth", auth_router())
|
Router::new().nest("/auth", auth_router())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,24 @@ pub mod permissions_repository;
|
|||||||
pub mod permissions_schema;
|
pub mod permissions_schema;
|
||||||
pub mod permissions_service;
|
pub mod permissions_service;
|
||||||
|
|
||||||
pub use permissions_controller::*;
|
// Export only essential types and functions from each submodule
|
||||||
pub use permissions_dto::*;
|
pub use permissions_controller::{
|
||||||
pub use permissions_enum::*;
|
get_permission_list,
|
||||||
pub use permissions_guard::*;
|
get_permission_by_id,
|
||||||
pub use permissions_repository::*;
|
post_create_permission,
|
||||||
pub use permissions_schema::*;
|
put_update_permission,
|
||||||
|
delete_permission
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use permissions_dto::{
|
||||||
|
PermissionsRequestDto,
|
||||||
|
PermissionsUpdateRequestDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use permissions_enum::PermissionsEnum;
|
||||||
|
pub use permissions_guard::permissions_guard;
|
||||||
|
pub use permissions_repository::PermissionsRepository;
|
||||||
|
pub use permissions_schema::PermissionsSchema;
|
||||||
|
|
||||||
pub fn permissions_router() -> Router {
|
pub fn permissions_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|||||||
@@ -10,12 +10,26 @@ pub mod roles_repository;
|
|||||||
pub mod roles_schema;
|
pub mod roles_schema;
|
||||||
pub mod roles_service;
|
pub mod roles_service;
|
||||||
|
|
||||||
pub use roles_controller::*;
|
// Export only essential types and functions from each submodule
|
||||||
pub use roles_dto::*;
|
pub use roles_controller::{
|
||||||
pub use roles_enum::*;
|
get_role_list,
|
||||||
pub use roles_repository::*;
|
get_role_by_id,
|
||||||
pub use roles_schema::*;
|
post_create_role,
|
||||||
pub use roles_service::*;
|
put_update_role,
|
||||||
|
delete_role
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use roles_dto::{
|
||||||
|
RolesRequestCreateDto,
|
||||||
|
RolesRequestUpdateDto,
|
||||||
|
RolesDetailItemDto,
|
||||||
|
RolesListItemDto,
|
||||||
|
RolesDetailQueryDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use roles_enum::RolesEnum;
|
||||||
|
pub use roles_repository::RolesRepository;
|
||||||
|
pub use roles_schema::RolesSchema;
|
||||||
|
|
||||||
pub fn roles_router() -> Router {
|
pub fn roles_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|||||||
@@ -5,15 +5,50 @@ pub mod teams_repository;
|
|||||||
pub mod teams_schema;
|
pub mod teams_schema;
|
||||||
pub mod teams_service;
|
pub mod teams_service;
|
||||||
|
|
||||||
pub use admin_teams_controller::{admin_teams_router, get_all_teams as admin_get_all_teams, get_team_by_id as admin_get_team_by_id, get_team_members as admin_get_team_members, create_team as admin_create_team, update_team as admin_update_team, delete_team as admin_delete_team, invite_team_members as admin_invite_team_members};
|
|
||||||
pub use teams_controller::{teams_router as user_teams_router, get_team_list, get_team_by_id as user_get_team_by_id, get_team_members as user_get_team_members};
|
|
||||||
pub use teams_dto::*;
|
|
||||||
pub use teams_repository::*;
|
|
||||||
pub use teams_schema::*;
|
|
||||||
pub use teams_service::*;
|
|
||||||
|
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
|
// Export only essential types and functions from each submodule
|
||||||
|
pub use admin_teams_controller::{
|
||||||
|
admin_teams_router,
|
||||||
|
get_all_teams as admin_get_all_teams,
|
||||||
|
get_team_by_id as admin_get_team_by_id,
|
||||||
|
get_team_members as admin_get_team_members,
|
||||||
|
create_team as admin_create_team,
|
||||||
|
update_team as admin_update_team,
|
||||||
|
delete_team as admin_delete_team,
|
||||||
|
invite_team_members as admin_invite_team_members
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use teams_controller::{
|
||||||
|
teams_router as user_teams_router,
|
||||||
|
get_team_list,
|
||||||
|
get_team_by_id as user_get_team_by_id,
|
||||||
|
get_team_members as user_get_team_members
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use teams_dto::{
|
||||||
|
TeamsCreateRequestDto,
|
||||||
|
TeamsUpdateRequestDto,
|
||||||
|
TeamInviteRequestDto,
|
||||||
|
TeamMemberDto,
|
||||||
|
TeamsListItemDto,
|
||||||
|
TeamsDetailItemDto,
|
||||||
|
PublicTeamsListItemDto,
|
||||||
|
PublicTeamsDetailItemDto,
|
||||||
|
AdminTeamsListItemDto,
|
||||||
|
AdminTeamsDetailItemDto,
|
||||||
|
TeamAcceptInvitationRequestDto,
|
||||||
|
TeamsSearchQueryDto,
|
||||||
|
TeamsDetailQueryDto,
|
||||||
|
TeamsListQueryDto,
|
||||||
|
TeamMembersQueryDto,
|
||||||
|
TeamInvitationsQueryDto,
|
||||||
|
MemberTeamsDetailItemDto
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use teams_repository::TeamsRepository;
|
||||||
|
pub use teams_schema::{TeamsSchema, TeamMembersSchema, TeamInvitationsSchema};
|
||||||
|
|
||||||
pub fn teams_router() -> Router {
|
pub fn teams_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
// Public routes
|
// Public routes
|
||||||
|
|||||||
@@ -9,11 +9,31 @@ pub mod users_repository;
|
|||||||
pub mod users_schema;
|
pub mod users_schema;
|
||||||
pub mod users_service;
|
pub mod users_service;
|
||||||
|
|
||||||
pub use users_controller::*;
|
// Export only essential types and functions from each submodule
|
||||||
pub use users_dto::*;
|
pub use users_controller::{
|
||||||
pub use users_repository::*;
|
get_user_list,
|
||||||
pub use users_schema::*;
|
get_user_by_id,
|
||||||
pub use users_service::*;
|
get_user_me,
|
||||||
|
post_create_user,
|
||||||
|
put_update_user,
|
||||||
|
put_update_user_me,
|
||||||
|
delete_user,
|
||||||
|
patch_user_active_status,
|
||||||
|
upload_file
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use users_dto::{
|
||||||
|
UsersActiveInactiveRequestDto,
|
||||||
|
UsersCreateRequestDto,
|
||||||
|
UsersUpdateRequestDto,
|
||||||
|
UsersSetNewPasswordRequestDto,
|
||||||
|
UsersDetailItemDto,
|
||||||
|
UsersListItemDto,
|
||||||
|
UsersListQueryDto,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use users_repository::UsersRepository;
|
||||||
|
pub use users_schema::UsersSchema;
|
||||||
|
|
||||||
pub fn users_router() -> Router {
|
pub fn users_router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|||||||
@@ -1,29 +1,83 @@
|
|||||||
|
//! Argon2 password hashing utilities.
|
||||||
|
//!
|
||||||
|
//! This module provides secure password hashing and verification using the Argon2 algorithm.
|
||||||
|
//! The hashing parameters are configured for a balance between security and performance.
|
||||||
|
|
||||||
use argon2::{
|
use argon2::{
|
||||||
Argon2,
|
Argon2,
|
||||||
password_hash::{
|
password_hash::{
|
||||||
Error, PasswordHash, PasswordHasher, PasswordVerifier, SaltString,
|
Error, PasswordHash, PasswordHasher, PasswordVerifier, SaltString,
|
||||||
rand_core::OsRng,
|
rand_core::OsRng,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configuration constants for Argon2 hashing
|
||||||
|
const MEMORY_COST: u32 = 1024; // 1MB
|
||||||
|
const TIME_COST: u32 = 1; // 1 iteration
|
||||||
|
const PARALLELISM: u32 = 1; // 1 thread
|
||||||
|
|
||||||
|
/// Hash a password using Argon2id algorithm.
|
||||||
|
///
|
||||||
|
/// This function generates a cryptographically secure salt and hashes the password
|
||||||
|
/// with predefined parameters optimized for a balance of security and performance.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `password` - The plain text password to hash
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(String)` - The hashed password in PHC string format
|
||||||
|
/// * `Err(Error)` - If hashing fails
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use imphnen_libs::hash_password;
|
||||||
|
///
|
||||||
|
/// let hash = hash_password("my_password")?;
|
||||||
|
/// assert!(hash.starts_with("$argon2id$"));
|
||||||
|
/// # Ok::<(), argon2::password_hash::Error>(())
|
||||||
|
/// ```
|
||||||
pub fn hash_password(password: &str) -> Result<String, Error> {
|
pub fn hash_password(password: &str) -> Result<String, Error> {
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
let argon2 = Argon2::new(
|
let argon2 = Argon2::new(
|
||||||
argon2::Algorithm::Argon2id,
|
argon2::Algorithm::Argon2id,
|
||||||
argon2::Version::V0x13,
|
argon2::Version::V0x13,
|
||||||
argon2::Params::new(1024, 1, 1, None).unwrap() // 1MB, 1 iteration, 1 thread (faster, less secure)
|
argon2::Params::new(MEMORY_COST, TIME_COST, PARALLELISM, None).unwrap(),
|
||||||
);
|
);
|
||||||
let password_hash = argon2
|
|
||||||
.hash_password(password.as_bytes(), &salt)?
|
let password_hash = argon2
|
||||||
.to_string();
|
.hash_password(password.as_bytes(), &salt)?
|
||||||
Ok(password_hash)
|
.to_string();
|
||||||
|
Ok(password_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify a password against its hash.
|
||||||
|
///
|
||||||
|
/// This function checks if the provided password matches the given hash.
|
||||||
|
/// Returns false for both incorrect passwords and invalid hash formats.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `password` - The plain text password to verify
|
||||||
|
/// * `hash` - The hashed password in PHC string format
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(bool)` - true if password matches, false otherwise
|
||||||
|
/// * `Err(Error)` - If hash parsing fails
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use imphnen_libs::{hash_password, verify_password};
|
||||||
|
///
|
||||||
|
/// let hash = hash_password("my_password")?;
|
||||||
|
/// assert!(verify_password("my_password", &hash)?);
|
||||||
|
/// assert!(!verify_password("wrong_password", &hash)?);
|
||||||
|
/// # Ok::<(), argon2::password_hash::Error>(())
|
||||||
|
/// ```
|
||||||
pub fn verify_password(password: &str, hash: &str) -> Result<bool, Error> {
|
pub fn verify_password(password: &str, hash: &str) -> Result<bool, Error> {
|
||||||
let parsed_hash = PasswordHash::new(hash)?;
|
let parsed_hash = PasswordHash::new(hash)?;
|
||||||
let argon2 = Argon2::default();
|
let argon2 = Argon2::default();
|
||||||
match argon2.verify_password(password.as_bytes(), &parsed_hash) {
|
|
||||||
Ok(_) => Ok(true),
|
match argon2.verify_password(password.as_bytes(), &parsed_hash) {
|
||||||
Err(_) => Ok(false),
|
Ok(_) => Ok(true),
|
||||||
}
|
Err(_) => Ok(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,80 @@
|
|||||||
|
//! Axum server initialization utilities.
|
||||||
|
//!
|
||||||
|
//! This module provides utilities for initializing and running an Axum web server
|
||||||
|
//! with SurrealDB connections for both WebSocket and in-memory databases.
|
||||||
|
|
||||||
use crate::{surrealdb_init_mem, surrealdb_init_ws, SurrealMemClient, SurrealWsClient};
|
use crate::{surrealdb_init_mem, surrealdb_init_ws, SurrealMemClient, SurrealWsClient};
|
||||||
use axum::{Router, serve};
|
use axum::{Router, serve};
|
||||||
use std::{future::Future, net::SocketAddr};
|
use std::{future::Future, net::SocketAddr};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use crate::enviroment::ENV;
|
use crate::enviroment::ENV;
|
||||||
|
|
||||||
|
/// Initialize and start the Axum server with SurrealDB connections.
|
||||||
|
///
|
||||||
|
/// This function sets up both WebSocket and in-memory SurrealDB connections,
|
||||||
|
/// builds the router using the provided function, and starts the server.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `router_fn` - A function that takes SurrealDB clients and returns a Router
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// This function will panic if:
|
||||||
|
/// - SurrealDB initialization fails
|
||||||
|
/// - TCP listener binding fails
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// use axum::Router;
|
||||||
|
/// use imphnen_libs::{axum_init, SurrealWsClient, SurrealMemClient};
|
||||||
|
///
|
||||||
|
/// async fn create_router(ws: SurrealWsClient, mem: SurrealMemClient) -> Router {
|
||||||
|
/// Router::new()
|
||||||
|
/// // Add your routes here
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// axum_init(create_router).await;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub async fn axum_init<F, Fut>(router_fn: F)
|
pub async fn axum_init<F, Fut>(router_fn: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(SurrealWsClient, SurrealMemClient) -> Fut,
|
F: FnOnce(SurrealWsClient, SurrealMemClient) -> Fut,
|
||||||
Fut: Future<Output = Router>,
|
Fut: Future<Output = Router>,
|
||||||
{
|
{
|
||||||
let env = &ENV;
|
let env = &ENV;
|
||||||
|
|
||||||
let surrealdb_ws = surrealdb_init_ws().await.expect("Failed surrealdb ws");
|
// Initialize SurrealDB connections
|
||||||
|
log::info!("Initializing SurrealDB connections...");
|
||||||
|
let surrealdb_ws = surrealdb_init_ws()
|
||||||
|
.await
|
||||||
|
.expect("Failed to initialize SurrealDB WebSocket connection");
|
||||||
|
|
||||||
let surrealdb_mem = surrealdb_init_mem().await.expect("Failed surrealdb mem");
|
let surrealdb_mem = surrealdb_init_mem()
|
||||||
|
.await
|
||||||
|
.expect("Failed to initialize SurrealDB in-memory connection");
|
||||||
|
|
||||||
let router = router_fn(surrealdb_ws, surrealdb_mem).await;
|
log::info!("SurrealDB connections established successfully");
|
||||||
|
|
||||||
let port = env.port;
|
// Build the router
|
||||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
let router = router_fn(surrealdb_ws, surrealdb_mem).await;
|
||||||
let listener = TcpListener::bind(&addr).await.unwrap();
|
|
||||||
|
|
||||||
if let Err(err) = serve(listener, router).await {
|
// Start the server
|
||||||
log::error!("Server failed to start: {}", err);
|
let port = env.port;
|
||||||
}
|
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||||
|
log::info!("Starting server on {}", addr);
|
||||||
|
|
||||||
|
let listener = TcpListener::bind(&addr)
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
log::error!("Failed to bind to address {}: {}", addr, e);
|
||||||
|
panic!("Server binding failed: {}", e);
|
||||||
|
});
|
||||||
|
|
||||||
|
log::info!("Server listening on {}", addr);
|
||||||
|
|
||||||
|
if let Err(err) = serve(listener, router).await {
|
||||||
|
log::error!("Server encountered an error: {}", err);
|
||||||
|
panic!("Server failed: {}", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
//! Environment configuration module using once_cell::sync::Lazy for one-time loading.
|
//! Environment configuration module using once_cell::sync::Lazy for one-time loading.
|
||||||
|
//!
|
||||||
|
//! This module provides centralized configuration management for the application.
|
||||||
|
//! All environment variables are loaded once at startup and cached for performance.
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
// Logging for warnings if .env is missing
|
|
||||||
use log::{warn, info};
|
use log::{warn, info};
|
||||||
|
|
||||||
/// Struct holding all environment configuration.
|
/// Struct holding all environment configuration.
|
||||||
|
///
|
||||||
|
/// This struct contains all configuration values loaded from environment variables.
|
||||||
|
/// Sensitive values are masked in debug output for security.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
@@ -16,7 +21,6 @@ pub struct Env {
|
|||||||
pub surrealdb_password: String,
|
pub surrealdb_password: String,
|
||||||
pub surrealdb_namespace: String,
|
pub surrealdb_namespace: String,
|
||||||
pub surrealdb_dbname: String,
|
pub surrealdb_dbname: String,
|
||||||
pub surrealdb_url_ws: String,
|
|
||||||
pub smtp_email: String,
|
pub smtp_email: String,
|
||||||
pub smtp_password: String,
|
pub smtp_password: String,
|
||||||
pub smtp_name: String,
|
pub smtp_name: String,
|
||||||
@@ -48,7 +52,6 @@ impl std::fmt::Debug for Env {
|
|||||||
.field("surrealdb_password", &"***")
|
.field("surrealdb_password", &"***")
|
||||||
.field("surrealdb_namespace", &self.surrealdb_namespace)
|
.field("surrealdb_namespace", &self.surrealdb_namespace)
|
||||||
.field("surrealdb_dbname", &self.surrealdb_dbname)
|
.field("surrealdb_dbname", &self.surrealdb_dbname)
|
||||||
.field("surrealdb_url_ws", &self.surrealdb_url_ws)
|
|
||||||
.field("smtp_email", &self.smtp_email)
|
.field("smtp_email", &self.smtp_email)
|
||||||
.field("smtp_password", &"***")
|
.field("smtp_password", &"***")
|
||||||
.field("smtp_name", &self.smtp_name)
|
.field("smtp_name", &self.smtp_name)
|
||||||
@@ -69,7 +72,17 @@ impl std::fmt::Debug for Env {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to get env var with warning if not set.
|
/// Get environment variable with warning if not set.
|
||||||
|
///
|
||||||
|
/// This helper function attempts to read an environment variable and logs a warning
|
||||||
|
/// if it's not set, falling back to the provided default value.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `key` - The environment variable name
|
||||||
|
/// * `default` - The default value to use if the variable is not set
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// The environment variable value or the default
|
||||||
fn get_env_with_warning(key: &str, default: &str) -> String {
|
fn get_env_with_warning(key: &str, default: &str) -> String {
|
||||||
match env::var(key) {
|
match env::var(key) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
@@ -80,49 +93,113 @@ fn get_env_with_warning(key: &str, default: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads environment variables from .env and system, only once.
|
/// Parse environment variable as u16 with fallback.
|
||||||
pub static ENV: Lazy<Env> = Lazy::new(|| {
|
///
|
||||||
// Try to load .env file, log a warning if not found, proceed regardless.
|
/// # Arguments
|
||||||
match dotenvy::dotenv() {
|
/// * `key` - The environment variable name
|
||||||
Ok(_) => {}
|
/// * `default` - The default numeric value
|
||||||
Err(dotenvy::Error::Io(ref e)) if e.kind() == std::io::ErrorKind::NotFound => {
|
///
|
||||||
warn!(".env file not found, falling back to system environment variables");
|
/// # Returns
|
||||||
|
/// The parsed u16 value or the default if parsing fails
|
||||||
|
fn get_env_u16_with_warning(key: &str, default: u16) -> u16 {
|
||||||
|
match env::var(key) {
|
||||||
|
Ok(val) => val.parse().unwrap_or_else(|_| {
|
||||||
|
warn!("Environment variable '{}' has invalid value '{}'. Using default: {}", key, val, default);
|
||||||
|
default
|
||||||
|
}),
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Environment variable '{}' is not set. Using default: {}", key, default);
|
||||||
|
default
|
||||||
}
|
}
|
||||||
Err(_) => {}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse environment variable as bool with fallback.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `key` - The environment variable name
|
||||||
|
/// * `default` - The default boolean value
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// The parsed boolean value or the default if parsing fails
|
||||||
|
fn get_env_bool_with_warning(key: &str, default: bool) -> bool {
|
||||||
|
match env::var(key) {
|
||||||
|
Ok(val) => val.parse().unwrap_or_else(|_| {
|
||||||
|
warn!("Environment variable '{}' has invalid value '{}'. Using default: {}", key, val, default);
|
||||||
|
default
|
||||||
|
}),
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Environment variable '{}' is not set. Using default: {}", key, default);
|
||||||
|
default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Global environment configuration loaded once at startup.
|
||||||
|
///
|
||||||
|
/// This static variable loads all environment configuration exactly once
|
||||||
|
/// and caches it for the lifetime of the application.
|
||||||
|
pub static ENV: Lazy<Env> = Lazy::new(|| {
|
||||||
|
// Load .env file if present
|
||||||
|
load_dotenv_file();
|
||||||
|
|
||||||
let env = Env {
|
let env = Env {
|
||||||
port: get_env_with_warning("PORT", "3000")
|
// Server configuration
|
||||||
.parse()
|
port: get_env_u16_with_warning("PORT", 3000),
|
||||||
.unwrap_or(3000),
|
|
||||||
|
// JWT secrets
|
||||||
access_token_secret: get_env_with_warning("ACCESS_TOKEN_SECRET", "default_access_secret"),
|
access_token_secret: get_env_with_warning("ACCESS_TOKEN_SECRET", "default_access_secret"),
|
||||||
refresh_token_secret: get_env_with_warning("REFRESH_TOKEN_SECRET", "default_refresh_secret"),
|
refresh_token_secret: get_env_with_warning("REFRESH_TOKEN_SECRET", "default_refresh_secret"),
|
||||||
|
|
||||||
|
// SurrealDB configuration
|
||||||
surrealdb_url: get_env_with_warning("SURREALDB_URL", "http://localhost:8000"),
|
surrealdb_url: get_env_with_warning("SURREALDB_URL", "http://localhost:8000"),
|
||||||
surrealdb_username: get_env_with_warning("SURREALDB_USERNAME", "root"),
|
surrealdb_username: get_env_with_warning("SURREALDB_USERNAME", "root"),
|
||||||
surrealdb_password: get_env_with_warning("SURREALDB_PASSWORD", "root"),
|
surrealdb_password: get_env_with_warning("SURREALDB_PASSWORD", "root"),
|
||||||
surrealdb_namespace: get_env_with_warning("SURREALDB_NAMESPACE", "namespace"),
|
surrealdb_namespace: get_env_with_warning("SURREALDB_NAMESPACE", "namespace"),
|
||||||
surrealdb_dbname: get_env_with_warning("SURREALDB_DBNAME", "database"),
|
surrealdb_dbname: get_env_with_warning("SURREALDB_DBNAME", "database"),
|
||||||
|
|
||||||
|
// SMTP configuration
|
||||||
smtp_email: get_env_with_warning("SMTP_EMAIL", "no-reply@example.com"),
|
smtp_email: get_env_with_warning("SMTP_EMAIL", "no-reply@example.com"),
|
||||||
smtp_password: get_env_with_warning("SMTP_PASSWORD", "default_smtp_password"),
|
smtp_password: get_env_with_warning("SMTP_PASSWORD", "default_smtp_password"),
|
||||||
smtp_name: get_env_with_warning("SMTP_NAME", "MyApp SMTP"),
|
smtp_name: get_env_with_warning("SMTP_NAME", "MyApp SMTP"),
|
||||||
smtp_host: get_env_with_warning("SMTP_HOST", "smtp.gmail.com"),
|
smtp_host: get_env_with_warning("SMTP_HOST", "smtp.gmail.com"),
|
||||||
|
|
||||||
|
// Redis configuration
|
||||||
redisdb_url: get_env_with_warning("REDISDB_URL", "localhost"),
|
redisdb_url: get_env_with_warning("REDISDB_URL", "localhost"),
|
||||||
|
|
||||||
|
// Frontend URL
|
||||||
fe_url: get_env_with_warning("FE_URL", "http://localhost"),
|
fe_url: get_env_with_warning("FE_URL", "http://localhost"),
|
||||||
|
|
||||||
|
// Environment
|
||||||
rust_env: get_env_with_warning("RUST_ENV", "development"),
|
rust_env: get_env_with_warning("RUST_ENV", "development"),
|
||||||
|
|
||||||
|
// MinIO configuration
|
||||||
minio_endpoint: get_env_with_warning("MINIO_ENDPOINT", "http://localhost:9000"),
|
minio_endpoint: get_env_with_warning("MINIO_ENDPOINT", "http://localhost:9000"),
|
||||||
minio_bucket_name: get_env_with_warning("MINIO_BUCKET_NAME", "imphnen-uploads"),
|
minio_bucket_name: get_env_with_warning("MINIO_BUCKET_NAME", "imphnen-uploads"),
|
||||||
minio_access_key: get_env_with_warning("MINIO_ACCESS_KEY", "minio_access"),
|
minio_access_key: get_env_with_warning("MINIO_ACCESS_KEY", "minio_access"),
|
||||||
minio_secret_key: get_env_with_warning("MINIO_SECRET_KEY", "minio_secret"),
|
minio_secret_key: get_env_with_warning("MINIO_SECRET_KEY", "minio_secret"),
|
||||||
minio_region: get_env_with_warning("MINIO_REGION", "us-east-1"),
|
minio_region: get_env_with_warning("MINIO_REGION", "us-east-1"),
|
||||||
minio_secure: get_env_with_warning("MINIO_SECURE", "false")
|
minio_secure: get_env_bool_with_warning("MINIO_SECURE", false),
|
||||||
.parse()
|
|
||||||
.unwrap_or(false),
|
|
||||||
surrealdb_url_ws: String::new(),
|
|
||||||
// Google OAuth 2.1
|
// Google OAuth 2.1
|
||||||
google_client_id: get_env_with_warning("GOOGLE_CLIENT_ID", "default_google_client_id"),
|
google_client_id: get_env_with_warning("GOOGLE_CLIENT_ID", "default_google_client_id"),
|
||||||
google_client_secret: get_env_with_warning("GOOGLE_CLIENT_SECRET", "default_google_client_secret"),
|
google_client_secret: get_env_with_warning("GOOGLE_CLIENT_SECRET", "default_google_client_secret"),
|
||||||
google_redirect_url: get_env_with_warning("GOOGLE_REDIRECT_URL", "http://localhost:8000/api/v1/auth/google/callback"),
|
google_redirect_url: get_env_with_warning("GOOGLE_REDIRECT_URL", "http://localhost:8000/api/v1/auth/google/callback"),
|
||||||
};
|
};
|
||||||
info!("Loaded environment configuration: {:?}", env);
|
|
||||||
|
info!("Environment configuration loaded successfully");
|
||||||
env
|
env
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Load .env file if present, with appropriate logging.
|
||||||
|
fn load_dotenv_file() {
|
||||||
|
match dotenvy::dotenv() {
|
||||||
|
Ok(path) => info!("Loaded environment file: {:?}", path),
|
||||||
|
Err(dotenvy::Error::Io(ref e)) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
|
warn!(".env file not found, falling back to system environment variables");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Failed to load .env file: {}. Falling back to system environment variables", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,99 +1,161 @@
|
|||||||
|
//! JWT token encoding and decoding utilities.
|
||||||
|
//!
|
||||||
|
//! This module provides functions for creating and validating JWT tokens
|
||||||
|
//! for authentication purposes, including access tokens, refresh tokens,
|
||||||
|
//! and password reset tokens.
|
||||||
|
|
||||||
use crate::enviroment::ENV;
|
use crate::enviroment::ENV;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use chrono::{Duration, TimeDelta, Utc};
|
use chrono::{Duration, TimeDelta, Utc};
|
||||||
use jsonwebtoken::{
|
use jsonwebtoken::{
|
||||||
DecodingKey, EncodingKey, Header, TokenData, Validation, decode, encode,
|
DecodingKey, EncodingKey, Header, TokenData, Validation, decode, encode,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// JWT claims structure containing token payload information.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Claims {
|
pub struct Claims {
|
||||||
pub exp: usize,
|
/// Expiration timestamp
|
||||||
pub iat: usize,
|
pub exp: usize,
|
||||||
pub sub: String,
|
/// Issued at timestamp
|
||||||
|
pub iat: usize,
|
||||||
|
/// Subject (usually user identifier)
|
||||||
|
pub sub: String,
|
||||||
|
/// User ID
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Token configuration constants
|
||||||
|
const ACCESS_TOKEN_DURATION_MINUTES: i64 = 15;
|
||||||
|
const REFRESH_TOKEN_DURATION_DAYS: i64 = 1;
|
||||||
|
const RESET_TOKEN_DURATION_MINUTES: i64 = 5;
|
||||||
|
|
||||||
|
// Lazy-initialized headers and keys for performance
|
||||||
static ACCESS_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
static ACCESS_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
||||||
static ACCESS_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
static ACCESS_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
||||||
EncodingKey::from_secret(ENV.access_token_secret.as_ref())
|
EncodingKey::from_secret(ENV.access_token_secret.as_ref())
|
||||||
});
|
});
|
||||||
pub fn encode_access_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
|
||||||
let now = Utc::now();
|
|
||||||
let expire: TimeDelta = Duration::minutes(15);
|
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
|
||||||
let iat: usize = now.timestamp() as usize;
|
|
||||||
let claim = Claims { iat, exp, sub, user_id };
|
|
||||||
encode(
|
|
||||||
&ACCESS_HEADER,
|
|
||||||
&claim,
|
|
||||||
&ACCESS_KEY,
|
|
||||||
)
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encode_reset_password_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
|
||||||
let env = &ENV;
|
|
||||||
let secret: String = env.access_token_secret.clone();
|
|
||||||
let now = Utc::now();
|
|
||||||
let expire: TimeDelta = Duration::minutes(5);
|
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
|
||||||
let iat: usize = now.timestamp() as usize;
|
|
||||||
let claim = Claims { iat, exp, sub, user_id };
|
|
||||||
encode(
|
|
||||||
&Header::default(),
|
|
||||||
&claim,
|
|
||||||
&EncodingKey::from_secret(secret.as_ref()),
|
|
||||||
)
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_access_token(
|
|
||||||
jwt_token: &str,
|
|
||||||
) -> Result<TokenData<Claims>, StatusCode> {
|
|
||||||
let env = &ENV;
|
|
||||||
let secret: String = env.access_token_secret.clone();
|
|
||||||
let result: Result<TokenData<Claims>, StatusCode> = decode(
|
|
||||||
jwt_token,
|
|
||||||
&DecodingKey::from_secret(secret.as_ref()),
|
|
||||||
&Validation::default(),
|
|
||||||
)
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR);
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
static REFRESH_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
static REFRESH_HEADER: once_cell::sync::Lazy<Header> = once_cell::sync::Lazy::new(Header::default);
|
||||||
static REFRESH_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
static REFRESH_KEY: once_cell::sync::Lazy<EncodingKey> = once_cell::sync::Lazy::new(|| {
|
||||||
EncodingKey::from_secret(ENV.refresh_token_secret.as_ref())
|
EncodingKey::from_secret(ENV.refresh_token_secret.as_ref())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Create JWT claims with specified expiration duration.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `sub` - Subject identifier
|
||||||
|
/// * `user_id` - User ID
|
||||||
|
/// * `duration` - Token validity duration
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// JWT claims structure
|
||||||
|
fn create_claims(sub: String, user_id: String, duration: TimeDelta) -> Claims {
|
||||||
|
let now = Utc::now();
|
||||||
|
let exp: usize = (now + duration).timestamp() as usize;
|
||||||
|
let iat: usize = now.timestamp() as usize;
|
||||||
|
Claims { iat, exp, sub, user_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode a JWT token with the specified header and key.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `claims` - JWT claims to encode
|
||||||
|
/// * `header` - JWT header
|
||||||
|
/// * `key` - Encoding key
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Encoded JWT token or internal server error status
|
||||||
|
fn encode_token(claims: &Claims, header: &Header, key: &EncodingKey) -> Result<String, StatusCode> {
|
||||||
|
encode(header, claims, key).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a JWT token with the specified secret.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `token` - JWT token string
|
||||||
|
/// * `secret` - Secret key for decoding
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Decoded token data or internal server error status
|
||||||
|
fn decode_token(token: &str, secret: &str) -> Result<TokenData<Claims>, StatusCode> {
|
||||||
|
decode(
|
||||||
|
token,
|
||||||
|
&DecodingKey::from_secret(secret.as_ref()),
|
||||||
|
&Validation::default(),
|
||||||
|
)
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode an access token with 15-minute expiration.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `sub` - Subject identifier
|
||||||
|
/// * `user_id` - User ID
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Encoded JWT access token
|
||||||
|
pub fn encode_access_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
|
let claims = create_claims(sub, user_id, Duration::minutes(ACCESS_TOKEN_DURATION_MINUTES));
|
||||||
|
encode_token(&claims, &ACCESS_HEADER, &ACCESS_KEY)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode a refresh token with 1-day expiration.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `sub` - Subject identifier
|
||||||
|
/// * `user_id` - User ID
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Encoded JWT refresh token
|
||||||
pub fn encode_refresh_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
pub fn encode_refresh_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
let now = Utc::now();
|
let claims = create_claims(sub, user_id, Duration::days(REFRESH_TOKEN_DURATION_DAYS));
|
||||||
let expire: TimeDelta = Duration::days(1);
|
encode_token(&claims, &REFRESH_HEADER, &REFRESH_KEY)
|
||||||
let exp: usize = (now + expire).timestamp() as usize;
|
|
||||||
let iat: usize = now.timestamp() as usize;
|
|
||||||
let claim = Claims { iat, exp, sub, user_id };
|
|
||||||
encode(
|
|
||||||
&REFRESH_HEADER,
|
|
||||||
&claim,
|
|
||||||
&REFRESH_KEY,
|
|
||||||
)
|
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_refresh_token(
|
/// Encode a password reset token with 5-minute expiration.
|
||||||
jwt_token: &str,
|
///
|
||||||
) -> Result<TokenData<Claims>, StatusCode> {
|
/// # Arguments
|
||||||
let env = &ENV;
|
/// * `sub` - Subject identifier
|
||||||
let secret: String = env.refresh_token_secret.clone();
|
/// * `user_id` - User ID
|
||||||
let result: Result<TokenData<Claims>, StatusCode> = decode(
|
///
|
||||||
jwt_token,
|
/// # Returns
|
||||||
&DecodingKey::from_secret(secret.as_ref()),
|
/// Encoded JWT reset token
|
||||||
&Validation::default(),
|
pub fn encode_reset_password_token(sub: String, user_id: String) -> Result<String, StatusCode> {
|
||||||
)
|
let claims = create_claims(sub, user_id, Duration::minutes(RESET_TOKEN_DURATION_MINUTES));
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR);
|
let key = EncodingKey::from_secret(ENV.access_token_secret.as_ref());
|
||||||
result // Explicitly return result
|
encode_token(&claims, &Header::default(), &key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decode an access token.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `jwt_token` - JWT token string
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Decoded token data containing claims
|
||||||
|
pub fn decode_access_token(jwt_token: &str) -> Result<TokenData<Claims>, StatusCode> {
|
||||||
|
decode_token(jwt_token, &ENV.access_token_secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a refresh token.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `jwt_token` - JWT token string
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Decoded token data containing claims
|
||||||
|
pub fn decode_refresh_token(jwt_token: &str) -> Result<TokenData<Claims>, StatusCode> {
|
||||||
|
decode_token(jwt_token, &ENV.refresh_token_secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a simple JWT access token using user_id as both sub and user_id.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `user_id` - User identifier
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Encoded JWT access token
|
||||||
pub fn generate_jwt(user_id: &str) -> Result<String, StatusCode> {
|
pub fn generate_jwt(user_id: &str) -> Result<String, StatusCode> {
|
||||||
encode_access_token(user_id.to_string(), user_id.to_string())
|
encode_access_token(user_id.to_string(), user_id.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-28
@@ -1,35 +1,120 @@
|
|||||||
|
//! Email sending utilities using Lettre SMTP client.
|
||||||
|
//!
|
||||||
|
//! This module provides functionality for sending emails through SMTP
|
||||||
|
//! with proper error handling and logging.
|
||||||
|
|
||||||
use crate::enviroment::ENV;
|
use crate::enviroment::ENV;
|
||||||
use lettre::message::Mailbox;
|
use lettre::message::Mailbox;
|
||||||
use lettre::transport::smtp::authentication::Credentials;
|
use lettre::transport::smtp::authentication::Credentials;
|
||||||
use lettre::{Message, SmtpTransport, Transport};
|
use lettre::{Message, SmtpTransport, Transport};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Custom error type for email operations.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EmailError {
|
||||||
|
/// SMTP configuration error
|
||||||
|
SmtpConfig(String),
|
||||||
|
/// Message building error
|
||||||
|
MessageBuild(String),
|
||||||
|
/// SMTP transport error
|
||||||
|
Transport(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for EmailError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
EmailError::SmtpConfig(msg) => write!(f, "SMTP configuration error: {}", msg),
|
||||||
|
EmailError::MessageBuild(msg) => write!(f, "Message building error: {}", msg),
|
||||||
|
EmailError::Transport(msg) => write!(f, "SMTP transport error: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for EmailError {}
|
||||||
|
|
||||||
|
/// Send an email using the configured SMTP settings.
|
||||||
|
///
|
||||||
|
/// This function constructs and sends an email using the SMTP configuration
|
||||||
|
/// from environment variables. It handles sender name normalization and
|
||||||
|
/// proper error reporting.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `to` - Recipient email address
|
||||||
|
/// * `subject` - Email subject line
|
||||||
|
/// * `body` - Email body content (plain text)
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(())` - Email sent successfully
|
||||||
|
/// * `Err(EmailError)` - Email sending failed
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use imphnen_libs::send_email;
|
||||||
|
///
|
||||||
|
/// send_email("user@example.com", "Welcome!", "Hello, welcome to our service!")?;
|
||||||
|
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||||
|
/// ```
|
||||||
|
pub fn send_email(to: &str, subject: &str, body: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let env = &ENV;
|
||||||
|
|
||||||
|
// Build the email message
|
||||||
|
let message = build_email_message(to, subject, body, env)?;
|
||||||
|
|
||||||
|
// Create SMTP transport
|
||||||
|
let mailer = create_smtp_transport(env)?;
|
||||||
|
|
||||||
|
// Send the email
|
||||||
|
mailer.send(&message).map_err(|e| {
|
||||||
|
log::error!("Failed to send email to {}: {}", to, e);
|
||||||
|
Box::new(EmailError::Transport(e.to_string())) as Box<dyn Error>
|
||||||
|
})?;
|
||||||
|
|
||||||
|
log::info!("Email sent successfully to: {}", to);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an email message with proper sender and recipient configuration.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `to` - Recipient email address
|
||||||
|
/// * `subject` - Email subject
|
||||||
|
/// * `body` - Email body
|
||||||
|
/// * `env` - Environment configuration
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Email message or error
|
||||||
|
fn build_email_message(
|
||||||
|
to: &str,
|
||||||
|
subject: &str,
|
||||||
|
body: &str,
|
||||||
|
env: &crate::enviroment::Env,
|
||||||
|
) -> Result<Message, Box<dyn Error>> {
|
||||||
|
let sender_name = env.smtp_name.replace("-", " "); // Normalize sender name
|
||||||
|
|
||||||
|
Message::builder()
|
||||||
|
.from(Mailbox::new(Some(sender_name), env.smtp_email.parse()?))
|
||||||
|
.to(to.parse()?)
|
||||||
|
.subject(subject)
|
||||||
|
.body(body.to_string())
|
||||||
|
.map_err(|e| Box::new(EmailError::MessageBuild(e.to_string())) as Box<dyn Error>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create SMTP transport with authentication.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `env` - Environment configuration
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// Configured SMTP transport or error
|
||||||
|
fn create_smtp_transport(env: &crate::enviroment::Env) -> Result<SmtpTransport, Box<dyn Error>> {
|
||||||
|
let credentials = Credentials::new(
|
||||||
|
env.smtp_email.clone(),
|
||||||
|
env.smtp_password.replace("-", " "), // Normalize password
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(SmtpTransport::relay(&env.smtp_host)?
|
||||||
|
.credentials(credentials)
|
||||||
|
.build())
|
||||||
|
|
||||||
pub fn send_email(
|
|
||||||
to: &str,
|
|
||||||
subject: &str,
|
|
||||||
body: &str,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let env = &ENV;
|
|
||||||
let host = env.smtp_host.clone();
|
|
||||||
let sender_email = env.smtp_email.clone();
|
|
||||||
let sender_name = env.smtp_name.clone();
|
|
||||||
let sender_password = env.smtp_password.clone();
|
|
||||||
let recipient_email = to;
|
|
||||||
let email = Message::builder()
|
|
||||||
.from(Mailbox::new(
|
|
||||||
Some(sender_name.replace("-", " ")),
|
|
||||||
sender_email.parse()?,
|
|
||||||
))
|
|
||||||
.to(recipient_email.parse()?)
|
|
||||||
.subject(subject)
|
|
||||||
.body(body.to_string())?;
|
|
||||||
let smtp_credentials =
|
|
||||||
Credentials::new(sender_email, sender_password.replace("-", " "));
|
|
||||||
let mailer = SmtpTransport::relay(&host)?
|
|
||||||
.credentials(smtp_credentials)
|
|
||||||
.build();
|
|
||||||
match mailer.send(&email) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(Box::new(e)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-9
@@ -9,15 +9,35 @@ pub mod minio;
|
|||||||
pub mod services;
|
pub mod services;
|
||||||
pub mod surrealdb;
|
pub mod surrealdb;
|
||||||
|
|
||||||
pub use argon::*;
|
pub use argon::{hash_password, verify_password};
|
||||||
pub use axum::*;
|
pub use axum::axum_init;
|
||||||
pub use enviroment::*;
|
pub use enviroment::{ENV, Env};
|
||||||
pub use imphnen_entities::*;
|
pub use imphnen_entities::{
|
||||||
pub use jsonwebtoken::*;
|
MessageResponseDto,
|
||||||
pub use lettre::*;
|
MetaRequestDto,
|
||||||
pub use minio::*;
|
MetaResponseDto,
|
||||||
pub use services::*;
|
ResponseSuccessDto,
|
||||||
pub use surrealdb::*;
|
ResponseListSuccessDto,
|
||||||
|
CountResult,
|
||||||
|
Error,
|
||||||
|
ExperienceDto,
|
||||||
|
EducationDto,
|
||||||
|
UsersDetailQueryDto,
|
||||||
|
PermissionsEnum,
|
||||||
|
PermissionsItemDto,
|
||||||
|
PermissionsQueryDto,
|
||||||
|
};
|
||||||
|
pub use jsonwebtoken::{
|
||||||
|
Claims, encode_access_token, encode_refresh_token, decode_access_token,
|
||||||
|
decode_refresh_token, encode_reset_password_token, generate_jwt
|
||||||
|
};
|
||||||
|
pub use lettre::send_email;
|
||||||
|
pub use minio::*; // Minio has many useful exports, keeping for now
|
||||||
|
pub use services::{UserLookupService, AuthRepositoryTrait};
|
||||||
|
pub use surrealdb::{
|
||||||
|
surrealdb_init_ws, surrealdb_init_mem, SurrealWsClient, SurrealMemClient,
|
||||||
|
ResourceEnum
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
|||||||
@@ -1,35 +1,105 @@
|
|||||||
|
//! SurrealDB client initialization and configuration.
|
||||||
|
//!
|
||||||
|
//! This module provides utilities for initializing SurrealDB connections
|
||||||
|
//! for both WebSocket and in-memory databases, along with resource definitions.
|
||||||
|
|
||||||
use crate::enviroment::ENV;
|
use crate::enviroment::ENV;
|
||||||
use surrealdb::engine::any;
|
use surrealdb::engine::any;
|
||||||
use surrealdb::engine::local::{Db, Mem};
|
use surrealdb::engine::local::{Db, Mem};
|
||||||
use surrealdb::opt::auth::Root;
|
use surrealdb::opt::auth::Root;
|
||||||
use surrealdb::{Result, Surreal};
|
use surrealdb::{Result, Surreal};
|
||||||
|
|
||||||
|
/// Type alias for SurrealDB WebSocket client.
|
||||||
pub type SurrealWsClient = Surreal<any::Any>;
|
pub type SurrealWsClient = Surreal<any::Any>;
|
||||||
|
|
||||||
|
/// Type alias for SurrealDB in-memory client.
|
||||||
pub type SurrealMemClient = Surreal<Db>;
|
pub type SurrealMemClient = Surreal<Db>;
|
||||||
|
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
pub use resource::*;
|
pub use resource::*;
|
||||||
|
|
||||||
|
/// Initialize a SurrealDB WebSocket client connection.
|
||||||
|
///
|
||||||
|
/// This function creates a connection to a SurrealDB instance via WebSocket,
|
||||||
|
/// authenticates with root credentials, and sets the namespace and database.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(SurrealWsClient)` - Successfully initialized WebSocket client
|
||||||
|
/// * `Err(surrealdb::Error)` - Connection, authentication, or configuration failed
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// use imphnen_libs::surrealdb_init_ws;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let client = surrealdb_init_ws().await?;
|
||||||
|
/// // Use client for database operations
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub async fn surrealdb_init_ws() -> Result<Surreal<any::Any>> {
|
pub async fn surrealdb_init_ws() -> Result<Surreal<any::Any>> {
|
||||||
let env = &ENV;
|
let env = &ENV;
|
||||||
let db = any::connect(&env.surrealdb_url).await?;
|
|
||||||
|
|
||||||
db.signin(Root {
|
log::info!("Initializing SurrealDB WebSocket connection to: {}", env.surrealdb_url);
|
||||||
username: &env.surrealdb_username,
|
|
||||||
password: &env.surrealdb_password,
|
// Connect to SurrealDB
|
||||||
})
|
let db = any::connect(&env.surrealdb_url).await?;
|
||||||
.await?;
|
log::debug!("WebSocket connection established");
|
||||||
db.use_ns(env.surrealdb_namespace.clone())
|
|
||||||
.use_db(env.surrealdb_dbname.clone())
|
// Authenticate
|
||||||
.await?;
|
db.signin(Root {
|
||||||
Ok(db)
|
username: &env.surrealdb_username,
|
||||||
|
password: &env.surrealdb_password,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
log::debug!("Authentication successful");
|
||||||
|
|
||||||
|
// Configure namespace and database
|
||||||
|
db.use_ns(&env.surrealdb_namespace)
|
||||||
|
.use_db(&env.surrealdb_dbname)
|
||||||
|
.await?;
|
||||||
|
log::info!("SurrealDB WebSocket client initialized with namespace '{}' and database '{}'",
|
||||||
|
env.surrealdb_namespace, env.surrealdb_dbname);
|
||||||
|
|
||||||
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize a SurrealDB in-memory client.
|
||||||
|
///
|
||||||
|
/// This function creates an in-memory SurrealDB instance and configures
|
||||||
|
/// the namespace and database for use.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(SurrealMemClient)` - Successfully initialized in-memory client
|
||||||
|
/// * `Err(surrealdb::Error)` - Initialization or configuration failed
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// use imphnen_libs::surrealdb_init_mem;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let client = surrealdb_init_mem().await?;
|
||||||
|
/// // Use client for in-memory database operations
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub async fn surrealdb_init_mem() -> Result<SurrealMemClient> {
|
pub async fn surrealdb_init_mem() -> Result<SurrealMemClient> {
|
||||||
let env = &ENV;
|
let env = &ENV;
|
||||||
let db = Surreal::new::<Mem>(()).await?;
|
|
||||||
db.use_ns(&env.surrealdb_namespace)
|
log::info!("Initializing SurrealDB in-memory database");
|
||||||
.use_db(&env.surrealdb_dbname)
|
|
||||||
.await?;
|
// Create in-memory database
|
||||||
Ok(db)
|
let db = Surreal::new::<Mem>(()).await?;
|
||||||
|
log::debug!("In-memory database created");
|
||||||
|
|
||||||
|
// Configure namespace and database
|
||||||
|
db.use_ns(&env.surrealdb_namespace)
|
||||||
|
.use_db(&env.surrealdb_dbname)
|
||||||
|
.await?;
|
||||||
|
log::info!("SurrealDB in-memory client initialized with namespace '{}' and database '{}'",
|
||||||
|
env.surrealdb_namespace, env.surrealdb_dbname);
|
||||||
|
|
||||||
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,138 @@
|
|||||||
|
//! SurrealDB resource definitions.
|
||||||
|
//!
|
||||||
|
//! This module defines the database table names used throughout the application.
|
||||||
|
//! Each resource corresponds to a SurrealDB table with the "app_" prefix.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
/// Database resource enumeration.
|
||||||
|
///
|
||||||
|
/// Represents all database tables used in the application.
|
||||||
|
/// Each variant corresponds to a SurrealDB table name.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ResourceEnum {
|
pub enum ResourceEnum {
|
||||||
OtpCache,
|
/// OTP cache table for temporary authentication codes
|
||||||
UsersCache,
|
OtpCache,
|
||||||
GachaItems,
|
/// User cache table for user session data
|
||||||
GachaClaims,
|
UsersCache,
|
||||||
GachaRolls,
|
/// Gacha items table
|
||||||
GachaCredits,
|
GachaItems,
|
||||||
Users,
|
/// Gacha claims table for user item claims
|
||||||
Roles,
|
GachaClaims,
|
||||||
Permissions,
|
/// Gacha rolls table for user roll history
|
||||||
RolesPermissions,
|
GachaRolls,
|
||||||
Events,
|
/// Gacha credits table for user currency
|
||||||
Testimonials,
|
GachaCredits,
|
||||||
Mentors,
|
/// Users table for user accounts
|
||||||
Teams,
|
Users,
|
||||||
TeamMembers,
|
/// Roles table for user roles
|
||||||
TeamInvitations,
|
Roles,
|
||||||
|
/// Permissions table for system permissions
|
||||||
|
Permissions,
|
||||||
|
/// Role-permission relationships table
|
||||||
|
RolesPermissions,
|
||||||
|
/// Events table for application events
|
||||||
|
Events,
|
||||||
|
/// Testimonials table for user testimonials
|
||||||
|
Testimonials,
|
||||||
|
/// Mentors table for mentor profiles
|
||||||
|
Mentors,
|
||||||
|
/// Teams table for user teams
|
||||||
|
Teams,
|
||||||
|
/// Team members table for team membership
|
||||||
|
TeamMembers,
|
||||||
|
/// Team invitations table for pending invitations
|
||||||
|
TeamInvitations,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ResourceEnum {
|
impl fmt::Display for ResourceEnum {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let str = match self {
|
let table_name = match self {
|
||||||
ResourceEnum::Users => "app_users",
|
ResourceEnum::Users => "app_users",
|
||||||
ResourceEnum::UsersCache => "app_users_cache",
|
ResourceEnum::UsersCache => "app_users_cache",
|
||||||
ResourceEnum::OtpCache => "app_otp_cache",
|
ResourceEnum::OtpCache => "app_otp_cache",
|
||||||
ResourceEnum::Roles => "app_roles",
|
ResourceEnum::Roles => "app_roles",
|
||||||
ResourceEnum::Permissions => "app_permissions",
|
ResourceEnum::Permissions => "app_permissions",
|
||||||
ResourceEnum::RolesPermissions => "app_roles_permissions",
|
ResourceEnum::RolesPermissions => "app_roles_permissions",
|
||||||
ResourceEnum::GachaItems => "app_gacha_items",
|
ResourceEnum::GachaItems => "app_gacha_items",
|
||||||
ResourceEnum::GachaClaims => "app_gacha_claims",
|
ResourceEnum::GachaClaims => "app_gacha_claims",
|
||||||
ResourceEnum::GachaRolls => "app_gacha_rolls",
|
ResourceEnum::GachaRolls => "app_gacha_rolls",
|
||||||
ResourceEnum::GachaCredits => "app_gacha_credits",
|
ResourceEnum::GachaCredits => "app_gacha_credits",
|
||||||
ResourceEnum::Events => "app_events",
|
ResourceEnum::Events => "app_events",
|
||||||
ResourceEnum::Testimonials => "app_testimonials",
|
ResourceEnum::Testimonials => "app_testimonials",
|
||||||
ResourceEnum::Mentors => "app_mentors",
|
ResourceEnum::Mentors => "app_mentors",
|
||||||
ResourceEnum::Teams => "app_teams",
|
ResourceEnum::Teams => "app_teams",
|
||||||
ResourceEnum::TeamMembers => "app_team_members",
|
ResourceEnum::TeamMembers => "app_team_members",
|
||||||
ResourceEnum::TeamInvitations => "app_team_invitations",
|
ResourceEnum::TeamInvitations => "app_team_invitations",
|
||||||
};
|
};
|
||||||
write!(f, "{str}")
|
write!(f, "{}", table_name)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceEnum {
|
||||||
|
/// Get the table name as a string slice.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// The SurrealDB table name for this resource
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use imphnen_libs::ResourceEnum;
|
||||||
|
///
|
||||||
|
/// let users = ResourceEnum::Users;
|
||||||
|
/// assert_eq!(users.as_str(), "app_users");
|
||||||
|
/// ```
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ResourceEnum::Users => "app_users",
|
||||||
|
ResourceEnum::UsersCache => "app_users_cache",
|
||||||
|
ResourceEnum::OtpCache => "app_otp_cache",
|
||||||
|
ResourceEnum::Roles => "app_roles",
|
||||||
|
ResourceEnum::Permissions => "app_permissions",
|
||||||
|
ResourceEnum::RolesPermissions => "app_roles_permissions",
|
||||||
|
ResourceEnum::GachaItems => "app_gacha_items",
|
||||||
|
ResourceEnum::GachaClaims => "app_gacha_claims",
|
||||||
|
ResourceEnum::GachaRolls => "app_gacha_rolls",
|
||||||
|
ResourceEnum::GachaCredits => "app_gacha_credits",
|
||||||
|
ResourceEnum::Events => "app_events",
|
||||||
|
ResourceEnum::Testimonials => "app_testimonials",
|
||||||
|
ResourceEnum::Mentors => "app_mentors",
|
||||||
|
ResourceEnum::Teams => "app_teams",
|
||||||
|
ResourceEnum::TeamMembers => "app_team_members",
|
||||||
|
ResourceEnum::TeamInvitations => "app_team_invitations",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this resource is cache-related.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// true if the resource is used for caching, false otherwise
|
||||||
|
pub fn is_cache(&self) -> bool {
|
||||||
|
matches!(self, ResourceEnum::OtpCache | ResourceEnum::UsersCache)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this resource is gacha-related.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// true if the resource is part of the gacha system, false otherwise
|
||||||
|
pub fn is_gacha(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
ResourceEnum::GachaItems
|
||||||
|
| ResourceEnum::GachaClaims
|
||||||
|
| ResourceEnum::GachaRolls
|
||||||
|
| ResourceEnum::GachaCredits
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this resource is user-related.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// true if the resource contains user data, false otherwise
|
||||||
|
pub fn is_user_related(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
ResourceEnum::Users | ResourceEnum::UsersCache | ResourceEnum::Mentors
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,28 +41,27 @@ pub async fn auth_middleware(
|
|||||||
|
|
||||||
// Try SurrealDB mem first
|
// Try SurrealDB mem first
|
||||||
let mem_db = &state.surrealdb_mem;
|
let mem_db = &state.surrealdb_mem;
|
||||||
let mut user_data: Option<UsersDetailQueryDto> = None;
|
let user_data = if let Ok(Some(user)) = mem_db.select::<Option<UsersDetailQueryDto>>(("users", &user_id)).await {
|
||||||
if let Ok(opt_user) = mem_db.select(("users", &user_id)).await {
|
if !user.is_deleted && !user.role.is_deleted {
|
||||||
if let Some(user) = opt_user {
|
Some(user)
|
||||||
let user: UsersDetailQueryDto = user;
|
} else {
|
||||||
if !user.is_deleted && !user.role.is_deleted {
|
None
|
||||||
user_data = Some(user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Fallback to main DB if not found in mem
|
// Fallback to main DB if not found in mem
|
||||||
let user_data = match user_data {
|
let user_data = if let Some(user) = user_data {
|
||||||
Some(user) => user,
|
user
|
||||||
None => {
|
} else {
|
||||||
match state.user_lookup_service.get_user_by_id_internal(&thing_id, &state).await {
|
match state.user_lookup_service.get_user_by_id_internal(&thing_id, &state).await {
|
||||||
Ok(user) => {
|
Ok(user) => {
|
||||||
// Optionally: insert into mem for future requests
|
// Cache in mem for future requests
|
||||||
let _: Result<Option<UsersDetailQueryDto>, _> = mem_db.update(("users", &user_id)).content(user.clone()).await;
|
let _: Result<Option<UsersDetailQueryDto>, _> = mem_db.update(("users", &user_id)).content(user.clone()).await;
|
||||||
user
|
user
|
||||||
},
|
},
|
||||||
Err(_) => return Ok(common_response(StatusCode::UNAUTHORIZED, "User not found")),
|
Err(_) => return Ok(common_response(StatusCode::UNAUTHORIZED, "User not found")),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ pub mod auth_middleware;
|
|||||||
pub mod cors_middleware;
|
pub mod cors_middleware;
|
||||||
pub mod permissions_middleware;
|
pub mod permissions_middleware;
|
||||||
|
|
||||||
pub use auth_middleware::*;
|
pub use auth_middleware::auth_middleware;
|
||||||
pub use cors_middleware::*;
|
pub use cors_middleware::cors_middleware;
|
||||||
pub use permissions_middleware::*;
|
pub use permissions_middleware::PermissionsMiddlewareLayer;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use imphnen_utils::{common_response, extract_email, extract_email_async};
|
|||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tower::{Layer, Service};
|
use tower::{Layer, Service};
|
||||||
|
|
||||||
|
/// Middleware layer for enforcing user permissions on requests.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PermissionsMiddlewareLayer {
|
pub struct PermissionsMiddlewareLayer {
|
||||||
app_state: AppState,
|
app_state: AppState,
|
||||||
@@ -42,6 +43,7 @@ pub struct PermissionsMiddleware<S> {
|
|||||||
permissions: Vec<PermissionsEnum>,
|
permissions: Vec<PermissionsEnum>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<S> Service<Request<Body>> for PermissionsMiddleware<S>
|
impl<S> Service<Request<Body>> for PermissionsMiddleware<S>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<Body>> + Clone + Send + 'static,
|
S: Service<Request<Body>, Response = Response<Body>> + Clone + Send + 'static,
|
||||||
|
|||||||
+70
-18
@@ -1,39 +1,91 @@
|
|||||||
pub mod logger;
|
|
||||||
pub mod bind_filter;
|
pub mod bind_filter;
|
||||||
|
pub mod csrf_token;
|
||||||
pub mod extract_email;
|
pub mod extract_email;
|
||||||
pub mod generate_date;
|
pub mod generate_date;
|
||||||
pub mod generate_otp;
|
pub mod generate_otp;
|
||||||
pub mod get_id;
|
pub mod get_id;
|
||||||
|
pub mod logger;
|
||||||
pub mod make_thing;
|
pub mod make_thing;
|
||||||
|
pub mod mock_test;
|
||||||
pub mod query_builder;
|
pub mod query_builder;
|
||||||
pub mod query_list;
|
pub mod query_list;
|
||||||
pub mod response_format;
|
pub mod response_format;
|
||||||
pub mod serde_helpers;
|
pub mod serde_helpers;
|
||||||
pub mod validator;
|
pub mod validator;
|
||||||
pub mod csrf_token;
|
|
||||||
|
|
||||||
pub use logger::init_logger;
|
// Internal module re-exports
|
||||||
pub use bind_filter::*;
|
pub use bind_filter::bind_filter_value;
|
||||||
|
pub use csrf_token::{generate_csrf_token, generate_oauth_csrf_token, validate_csrf_token, validate_oauth_csrf_token};
|
||||||
pub use extract_email::{extract_email, extract_email_async, extract_email_token, extract_email_token_async};
|
pub use extract_email::{extract_email, extract_email_async, extract_email_token, extract_email_token_async};
|
||||||
pub use generate_date::*;
|
pub use generate_date::get_iso_date;
|
||||||
pub use generate_otp::*;
|
pub use generate_otp::OtpManager;
|
||||||
pub use get_id::*;
|
pub use get_id::{extract_id, get_id};
|
||||||
pub use imphnen_entities::*;
|
pub use logger::init_logger;
|
||||||
pub use imphnen_libs::*;
|
pub use make_thing::{make_thing, make_thing_from_enum, make_thing_str};
|
||||||
pub use make_thing::*;
|
|
||||||
pub use query_builder::{
|
pub use query_builder::{
|
||||||
build_thing_condition,
|
|
||||||
build_multi_thing_condition,
|
build_multi_thing_condition,
|
||||||
execute_safe_update_query,
|
build_thing_condition,
|
||||||
execute_safe_count_query,
|
execute_safe_count_query,
|
||||||
ListQueryBuilder,
|
execute_safe_update_query,
|
||||||
DetailQueryBuilder,
|
DetailQueryBuilder,
|
||||||
|
ListQueryBuilder,
|
||||||
};
|
};
|
||||||
pub use query_list::QueryListBuilder;
|
pub use query_list::QueryListBuilder;
|
||||||
pub use response_format::*;
|
pub use response_format::{common_response, success_created_response, success_list_response, success_response};
|
||||||
pub use serde_helpers::{
|
pub use serde_helpers::{
|
||||||
option_thing_or_string, serialize_option_thing, serialize_thing,
|
deserialize_datetime,
|
||||||
string_or_empty_string, thing_or_string,
|
option_thing_or_string,
|
||||||
|
serialize_datetime,
|
||||||
|
serialize_option_thing,
|
||||||
|
serialize_thing,
|
||||||
|
string_or_empty_string,
|
||||||
|
thing_or_string,
|
||||||
|
};
|
||||||
|
pub use validator::validate_request;
|
||||||
|
|
||||||
|
// External crate re-exports
|
||||||
|
pub use imphnen_libs::{
|
||||||
|
AppState,
|
||||||
|
Claims,
|
||||||
|
CountResult,
|
||||||
|
EducationDto,
|
||||||
|
ENV,
|
||||||
|
Env,
|
||||||
|
Error,
|
||||||
|
ExperienceDto,
|
||||||
|
FileMetadata,
|
||||||
|
FileType,
|
||||||
|
MessageResponseDto,
|
||||||
|
MetaRequestDto,
|
||||||
|
MetaResponseDto,
|
||||||
|
MinioConfig,
|
||||||
|
MinioService,
|
||||||
|
PermissionsEnum,
|
||||||
|
PermissionsItemDto,
|
||||||
|
PermissionsQueryDto,
|
||||||
|
ResourceEnum,
|
||||||
|
ResponseListSuccessDto,
|
||||||
|
ResponseSuccessDto,
|
||||||
|
SurrealMemClient,
|
||||||
|
SurrealWsClient,
|
||||||
|
UploadRequest,
|
||||||
|
UploadResult,
|
||||||
|
UserLookupService,
|
||||||
|
UsersDetailQueryDto,
|
||||||
|
AuthRepositoryTrait,
|
||||||
|
axum_init,
|
||||||
|
create_minio_service_from_config,
|
||||||
|
decode_access_token,
|
||||||
|
decode_base64_file,
|
||||||
|
decode_refresh_token,
|
||||||
|
encode_access_token,
|
||||||
|
encode_refresh_token,
|
||||||
|
encode_reset_password_token,
|
||||||
|
extract_content_type_from_data_url,
|
||||||
|
generate_jwt,
|
||||||
|
hash_password,
|
||||||
|
send_email,
|
||||||
|
surrealdb_init_mem,
|
||||||
|
surrealdb_init_ws,
|
||||||
|
verify_password,
|
||||||
};
|
};
|
||||||
pub use validator::*;
|
|
||||||
pub use csrf_token::*;
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod permissions;
|
||||||
@@ -1 +1 @@
|
|||||||
pub mod mentor;
|
pub mod mentors;
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ mod auth_login_tests {
|
|||||||
use crate::mock_test::setup_all_test_environment;
|
use crate::mock_test::setup_all_test_environment;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use imphnen_iam::{
|
use imphnen_iam::{
|
||||||
v1::auth::{AuthLoginRequestDto, AuthService, AuthServiceTrait}, // Import AuthServiceTrait
|
v1::auth::AuthLoginRequestDto,
|
||||||
AppState, UsersRepository, UsersSchema,
|
AppState, UsersRepository, UsersSchema,
|
||||||
};
|
};
|
||||||
|
use imphnen_iam::v1::auth::auth_service::AuthService;
|
||||||
|
use imphnen_iam::v1::auth::AuthServiceTrait;
|
||||||
use serde_json::Value; // Import the new setup function
|
use serde_json::Value; // Import the new setup function
|
||||||
|
|
||||||
async fn setup_test_environment() -> AppState {
|
async fn setup_test_environment() -> AppState {
|
||||||
@@ -343,7 +345,7 @@ mod auth_login_tests {
|
|||||||
assert_eq!(parts.status, StatusCode::OK);
|
assert_eq!(parts.status, StatusCode::OK);
|
||||||
|
|
||||||
// Verify user was cached
|
// Verify user was cached
|
||||||
let auth_repo = imphnen_iam::AuthRepository::new(&state);
|
let auth_repo = imphnen_iam::AuthRepository::new(state.surrealdb_mem.clone());
|
||||||
let cached_user = auth_repo.query_get_stored_user(email.clone()).await;
|
let cached_user = auth_repo.query_get_stored_user(email.clone()).await;
|
||||||
assert!(cached_user.is_ok());
|
assert!(cached_user.is_ok());
|
||||||
assert_eq!(cached_user.unwrap().email, email);
|
assert_eq!(cached_user.unwrap().email, email);
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ mod auth_repository_test {
|
|||||||
UsersSchema,
|
UsersSchema,
|
||||||
};
|
};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use imphnen_iam::{AppState, RolesDetailQueryDto, UsersDetailQueryDto};
|
use imphnen_iam::{AppState, UsersDetailQueryDto};
|
||||||
|
use imphnen_entities::RolesDetailQueryDto;
|
||||||
use surrealdb::Uuid;
|
use surrealdb::Uuid;
|
||||||
|
|
||||||
async fn create_mock_user(state: &AppState, email: &str) -> UsersSchema {
|
async fn create_mock_user(state: &AppState, email: &str) -> UsersSchema {
|
||||||
@@ -53,8 +54,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_store_and_get_user() {
|
async fn test_store_and_get_user() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let email = generate_unique_email("forgot");
|
let email = generate_unique_email("forgot");
|
||||||
let mut user = create_mock_user(&app_state, &email).await;
|
let mut user = create_mock_user(&app_state, &email).await;
|
||||||
user.role = get_role_id("user", &app_state).await;
|
user.role = get_role_id("user", &app_state).await;
|
||||||
@@ -81,8 +82,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete_stored_user() {
|
async fn test_delete_stored_user() {
|
||||||
let state = setup_all_test_environment().await; // Use the new setup function
|
let state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let auth_repo = AuthRepository::new(&state);
|
let auth_repo = AuthRepository::new(state.surrealdb_mem.clone());
|
||||||
let email = "delete_me@example.com".to_string();
|
let email = "delete_me@example.com".to_string();
|
||||||
let mock_user = UsersDetailQueryDto {
|
let mock_user = UsersDetailQueryDto {
|
||||||
id: make_thing(&ResourceEnum::UsersCache.to_string(), &email),
|
id: make_thing(&ResourceEnum::UsersCache.to_string(), &email),
|
||||||
@@ -144,8 +145,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_store_and_get_otp() {
|
async fn test_store_and_get_otp() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let email = "otp_user@example.com".to_string();
|
let email = "otp_user@example.com".to_string();
|
||||||
let otp = 123456;
|
let otp = 123456;
|
||||||
let stored = repo.query_store_otp(email.clone(), otp).await;
|
let stored = repo.query_store_otp(email.clone(), otp).await;
|
||||||
@@ -157,8 +158,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete_stored_otp() {
|
async fn test_delete_stored_otp() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let email = "otp_del@example.com".to_string();
|
let email = "otp_del@example.com".to_string();
|
||||||
let otp = 654321;
|
let otp = 654321;
|
||||||
let store_res = repo.query_store_otp(email.clone(), otp).await;
|
let store_res = repo.query_store_otp(email.clone(), otp).await;
|
||||||
@@ -178,18 +179,17 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_expired_otp() {
|
async fn test_expired_otp() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let email = "expired_otp@example.com".to_string();
|
let email = "expired_otp@example.com".to_string();
|
||||||
let otp = 789012;
|
let otp = 789012;
|
||||||
let table = ResourceEnum::OtpCache.to_string();
|
let table = ResourceEnum::OtpCache.to_string();
|
||||||
let expires_at = Utc::now() - Duration::seconds(1);
|
let expires_at = Utc::now() - Duration::seconds(1);
|
||||||
let created: Result<Option<AuthOtpSchema>, surrealdb::Error> = repo
|
let created: Result<Option<AuthOtpSchema>, surrealdb::Error> = repo
|
||||||
.state
|
.db
|
||||||
.surrealdb_mem
|
.create((table.clone(), email.as_str()))
|
||||||
.create((table.clone(), email.as_str()))
|
.content(AuthOtpSchema { otp, expires_at })
|
||||||
.content(AuthOtpSchema { otp, expires_at })
|
.await;
|
||||||
.await;
|
|
||||||
assert!(
|
assert!(
|
||||||
created.is_ok(),
|
created.is_ok(),
|
||||||
"Failed to create expired OTP: {:?}",
|
"Failed to create expired OTP: {:?}",
|
||||||
@@ -210,8 +210,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_non_existent_stored_user_should_fail() {
|
async fn test_get_non_existent_stored_user_should_fail() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let result = repo
|
let result = repo
|
||||||
.query_get_stored_user("not_found@example.com".into())
|
.query_get_stored_user("not_found@example.com".into())
|
||||||
.await;
|
.await;
|
||||||
@@ -226,8 +226,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete_non_existent_user_should_fail() {
|
async fn test_delete_non_existent_user_should_fail() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let result = repo
|
let result = repo
|
||||||
.query_delete_stored_user("ghost@example.com".into())
|
.query_delete_stored_user("ghost@example.com".into())
|
||||||
.await;
|
.await;
|
||||||
@@ -242,8 +242,8 @@ mod auth_repository_test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_store_and_get_valid_otp() {
|
async fn test_store_and_get_valid_otp() {
|
||||||
let app_state = setup_all_test_environment().await; // Use the new setup function
|
let app_state = setup_all_test_environment().await; // Use the new setup function
|
||||||
let repo = AuthRepository::new(&app_state);
|
let repo = AuthRepository::new(app_state.surrealdb_mem.clone());
|
||||||
let email = "valid_otp@example.com";
|
let email = "valid_otp@example.com";
|
||||||
let otp = 654321;
|
let otp = 654321;
|
||||||
let store_result = repo.query_store_otp(email.into(), otp).await;
|
let store_result = repo.query_store_otp(email.into(), otp).await;
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
pub mod google_oauth_flow_test;
|
||||||
@@ -8,8 +8,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_create_role() {
|
async fn test_query_create_role() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
let role_name = "test_role_repo_create".to_string();
|
let role_name = "test_role_repo_create".to_string();
|
||||||
@@ -35,8 +35,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_role_by_name() {
|
async fn test_query_role_by_name() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
let role_name = "test_role_repo_by_name".to_string();
|
let role_name = "test_role_repo_by_name".to_string();
|
||||||
@@ -66,8 +66,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_role_list() {
|
async fn test_query_role_list() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
||||||
|
|
||||||
// Create test roles
|
// Create test roles
|
||||||
let role_names = vec![
|
let role_names = vec![
|
||||||
@@ -108,8 +108,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_update_role() {
|
async fn test_query_update_role() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
let original_name = "test_role_update_original".to_string();
|
let original_name = "test_role_update_original".to_string();
|
||||||
@@ -149,8 +149,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_delete_role() {
|
async fn test_query_delete_role() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
let repo = imphnen_iam::RolesRepository::new(&app_state);
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
let role_name = "test_role_delete".to_string();
|
let role_name = "test_role_delete".to_string();
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
|
#[cfg(test)]
|
||||||
pub mod teams_repository_test;
|
pub mod teams_repository_test;
|
||||||
|
#[cfg(test)]
|
||||||
pub mod teams_service_test;
|
pub mod teams_service_test;
|
||||||
@@ -49,8 +49,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_create_team() {
|
async fn test_create_team() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -81,8 +81,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_team_list() {
|
async fn test_team_list() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -116,8 +116,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_update_team() {
|
async fn test_update_team() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -148,8 +148,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete_team() {
|
async fn test_delete_team() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -175,8 +175,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_add_team_member() {
|
async fn test_add_team_member() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -250,8 +250,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_team_member_check() {
|
async fn test_team_member_check() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -296,8 +296,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_create_invitation() {
|
async fn test_create_invitation() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let inviter_id = Uuid::new_v4().to_string();
|
let inviter_id = Uuid::new_v4().to_string();
|
||||||
@@ -332,8 +332,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_teams() {
|
async fn test_search_teams() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
@@ -366,8 +366,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_remove_team_member() {
|
async fn test_remove_team_member() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let team_id = Uuid::new_v4().to_string();
|
let team_id = Uuid::new_v4().to_string();
|
||||||
let leader_id = Uuid::new_v4().to_string();
|
let leader_id = Uuid::new_v4().to_string();
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_create_team_service() {
|
async fn test_create_team_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let email = generate_unique_email("team_creator");
|
let email = generate_unique_email("team_creator");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -54,9 +54,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_team_service() {
|
async fn test_get_team_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let email = generate_unique_email("team_getter");
|
let email = generate_unique_email("team_getter");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -101,9 +101,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_update_team_service() {
|
async fn test_update_team_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let email = generate_unique_email("team_updater");
|
let email = generate_unique_email("team_updater");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -171,9 +171,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_invite_team_member_service() {
|
async fn test_invite_team_member_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let leader_email = generate_unique_email("team_leader");
|
let leader_email = generate_unique_email("team_leader");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -228,9 +228,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_leave_team_service() {
|
async fn test_leave_team_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let leader_email = generate_unique_email("leave_leader");
|
let leader_email = generate_unique_email("leave_leader");
|
||||||
let member_email = generate_unique_email("leave_member");
|
let member_email = generate_unique_email("leave_member");
|
||||||
@@ -309,9 +309,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_teams_service() {
|
async fn test_search_teams_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let email = generate_unique_email("search_creator");
|
let email = generate_unique_email("search_creator");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -374,9 +374,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete_team_service() {
|
async fn test_delete_team_service() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let email = generate_unique_email("delete_creator");
|
let email = generate_unique_email("delete_creator");
|
||||||
let role_id = get_role_id("mentee", &app_state).await;
|
let role_id = get_role_id("mentee", &app_state).await;
|
||||||
@@ -428,9 +428,9 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_unauthorized_operations() {
|
async fn test_unauthorized_operations() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let users_repo = UsersRepository::new(&app_state);
|
let users_repo = UsersRepository::new(&app_state);
|
||||||
let repo = TeamsRepository::new(&app_state);
|
let repo = TeamsRepository::new(&app_state);
|
||||||
|
|
||||||
let leader_email = generate_unique_email("auth_leader");
|
let leader_email = generate_unique_email("auth_leader");
|
||||||
let non_leader_email = generate_unique_email("auth_non_leader");
|
let non_leader_email = generate_unique_email("auth_non_leader");
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_create_user() {
|
async fn test_query_create_user() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
let role_id = get_role_id("user", &app_state).await;
|
let role_id = get_role_id("user", &app_state).await;
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
@@ -41,8 +41,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_user_by_email() {
|
async fn test_query_user_by_email() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
let role_id = get_role_id("user", &app_state).await;
|
let role_id = get_role_id("user", &app_state).await;
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
@@ -75,8 +75,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_user_by_email_not_found() {
|
async fn test_query_user_by_email_not_found() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
|
|
||||||
// Try to get non-existent user
|
// Try to get non-existent user
|
||||||
let result = repo.query_user_by_email("nonexistent@example.com".to_string()).await;
|
let result = repo.query_user_by_email("nonexistent@example.com".to_string()).await;
|
||||||
@@ -85,8 +85,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_update_user() {
|
async fn test_query_update_user() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
let role_id = get_role_id("user", &app_state).await;
|
let role_id = get_role_id("user", &app_state).await;
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
@@ -133,8 +133,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_delete_user() {
|
async fn test_query_delete_user() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
let role_id = get_role_id("user", &app_state).await;
|
let role_id = get_role_id("user", &app_state).await;
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
@@ -168,8 +168,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_query_user_list() {
|
async fn test_query_user_list() {
|
||||||
let app_state = crate::get_app_state().await;
|
let app_state = crate::get_app_state().await;
|
||||||
let repo = UsersRepository::new(&app_state);
|
let repo = UsersRepository::new(&app_state);
|
||||||
let role_id = get_role_id("user", &app_state).await;
|
let role_id = get_role_id("user", &app_state).await;
|
||||||
|
|
||||||
// Create test users
|
// Create test users
|
||||||
|
|||||||
+5
-4
@@ -1,7 +1,8 @@
|
|||||||
use ::surrealdb::Uuid;
|
use ::surrealdb::Uuid;
|
||||||
use ::surrealdb::sql;
|
use ::surrealdb::sql;
|
||||||
pub use imphnen_entities::*;
|
pub use imphnen_entities::MetaRequestDto;
|
||||||
pub use imphnen_iam::*;
|
pub use imphnen_iam::{ResourceEnum, RolesRepository, UsersRepository, AuthOtpSchema, AuthRepository, RolesDetailQueryDto, UsersDetailQueryDto, RolesRequestCreateDto, RolesRequestUpdateDto, RolesDetailItemDto, TeamsRepository, TeamsSchema, TeamMembersSchema, TeamInvitationsSchema, UsersSchema};
|
||||||
|
use imphnen_libs::AppState;
|
||||||
|
|
||||||
pub fn create_test_mentor(
|
pub fn create_test_mentor(
|
||||||
email: &str,
|
email: &str,
|
||||||
@@ -69,7 +70,7 @@ pub fn generate_unique_email(prefix: &str) -> String {
|
|||||||
format!("{}_{}@example.com", prefix, Uuid::new_v4())
|
format!("{}_{}@example.com", prefix, Uuid::new_v4())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_role_id(role_name: &str, state: &crate::AppState) -> sql::Thing {
|
pub async fn get_role_id(role_name: &str, state: &AppState) -> sql::Thing {
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
if let Ok(existing) = repo.query_role_by_name(role_name.into()).await {
|
if let Ok(existing) = repo.query_role_by_name(role_name.into()).await {
|
||||||
return make_thing(&ResourceEnum::Roles.to_string(), &existing.id);
|
return make_thing(&ResourceEnum::Roles.to_string(), &existing.id);
|
||||||
@@ -87,7 +88,7 @@ pub async fn get_role_id(role_name: &str, state: &crate::AppState) -> sql::Thing
|
|||||||
make_thing(&ResourceEnum::Roles.to_string(), &role.id)
|
make_thing(&ResourceEnum::Roles.to_string(), &role.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_app_state() -> crate::AppState {
|
pub async fn get_app_state() -> AppState {
|
||||||
create_mock_app_state().await
|
create_mock_app_state().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user