feat: v0.3.0 — standardize codebase, centralize infra, merge QR into CMS
- Enforce axum best practices across all 13 workspace crates (max 200 LOC/file, no comments, no unwrap, clean architecture) - Fix domain→infrastructure dependency inversions in imphnen-iam and imphnen-dimentorin - Extract imphnen-storage (MinIO) and imphnen-email (Lettre) as standalone crates - Centralize all config in ENV struct: CDN_URL, CORS_ALLOWED_ORIGINS - Centralize SMTP through imphnen-email; remove dead HackathonConfig - Centralize database: QR crate now shares main DB pool (single DATABASE_URL) - Rename QR users table to qr_users to avoid collision with main users table - Merge imphnen-qr into imphnen-cms/src/qr (13 crates, down from 14) - Restructure imphnen-hackathon flat modules into clean architecture - Remove all stale env vars from .env.example (SurrealDB, QR_JWT, Hackathon infra) - Fix Dockerfile to include all current workspace crates - Bump all crate versions 0.2.0 → 0.3.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
2ae43b3bcc
commit
331a4a4e88
@@ -1,3 +1,3 @@
|
||||
use crate::seaorm::common::audit_log;
|
||||
|
||||
pub type AuditLogSchema = audit_log::Model;
|
||||
use crate::seaorm::common::audit_log;
|
||||
|
||||
pub type AuditLogSchema = audit_log::Model;
|
||||
|
||||
@@ -1,35 +1,33 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct MessageResponseDto {
|
||||
pub message: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoParams)]
|
||||
pub struct MetaResponseDto {
|
||||
pub page: Option<u64>,
|
||||
pub per_page: Option<u64>,
|
||||
pub total: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResponseSuccessDto<T: Serialize> {
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResponseListSuccessDto<T: Serialize> {
|
||||
pub data: T,
|
||||
pub meta: Option<MetaResponseDto>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ErrorDto {
|
||||
pub status: u16,
|
||||
pub message: String,
|
||||
pub details: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct MessageResponseDto {
|
||||
pub message: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoParams)]
|
||||
pub struct MetaResponseDto {
|
||||
pub page: Option<u64>,
|
||||
pub per_page: Option<u64>,
|
||||
pub total: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResponseSuccessDto<T: Serialize> {
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ResponseListSuccessDto<T: Serialize> {
|
||||
pub data: T,
|
||||
pub meta: Option<MetaResponseDto>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ErrorDto {
|
||||
pub status: u16,
|
||||
pub message: String,
|
||||
pub details: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
pub mod error {
|
||||
use axum::Json;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::response::Response;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("database error: {0}")]
|
||||
Db(String),
|
||||
#[error("anyhow error: {0}")]
|
||||
Anyhow(#[from] anyhow::Error),
|
||||
#[error("HTTP status code error: {0}")]
|
||||
StatusCode(StatusCode),
|
||||
#[error("authentication error: {0}")]
|
||||
Auth(String),
|
||||
#[error("validation error: {0}")]
|
||||
Validation(String),
|
||||
}
|
||||
|
||||
impl IntoResponse for Error {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, error_message) = match self {
|
||||
Error::Db(detail) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Database error: {detail}"),
|
||||
),
|
||||
Error::Anyhow(detail) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Internal server error: {detail}"),
|
||||
),
|
||||
Error::StatusCode(s) => (s, format!("HTTP error: {s}")),
|
||||
Error::Auth(detail) => (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
format!("Authentication error: {detail}"),
|
||||
),
|
||||
Error::Validation(detail) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("Validation error: {detail}"),
|
||||
),
|
||||
};
|
||||
(status, Json(error_message)).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StatusCode> for Error {
|
||||
fn from(status: StatusCode) -> Self {
|
||||
Self::StatusCode(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod error {
|
||||
use axum::Json;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::response::Response;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("database error: {0}")]
|
||||
Db(String),
|
||||
#[error("anyhow error: {0}")]
|
||||
Anyhow(#[from] anyhow::Error),
|
||||
#[error("HTTP status code error: {0}")]
|
||||
StatusCode(StatusCode),
|
||||
#[error("authentication error: {0}")]
|
||||
Auth(String),
|
||||
#[error("validation error: {0}")]
|
||||
Validation(String),
|
||||
}
|
||||
|
||||
impl IntoResponse for Error {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, error_message) = match self {
|
||||
Error::Db(detail) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Database error: {detail}"),
|
||||
),
|
||||
Error::Anyhow(detail) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Internal server error: {detail}"),
|
||||
),
|
||||
Error::StatusCode(s) => (s, format!("HTTP error: {s}")),
|
||||
Error::Auth(detail) => (
|
||||
StatusCode::UNAUTHORIZED,
|
||||
format!("Authentication error: {detail}"),
|
||||
),
|
||||
Error::Validation(detail) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("Validation error: {detail}"),
|
||||
),
|
||||
};
|
||||
(status, Json(error_message)).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StatusCode> for Error {
|
||||
fn from(status: StatusCode) -> Self {
|
||||
Self::StatusCode(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-29
@@ -1,29 +1,24 @@
|
||||
pub mod common_dto;
|
||||
pub mod error_dto;
|
||||
pub mod users;
|
||||
pub mod permissions;
|
||||
pub mod audit_log;
|
||||
pub mod seaorm;
|
||||
|
||||
// Explicit common_dto exports
|
||||
pub use common_dto::ErrorDto;
|
||||
pub use common_dto::MessageResponseDto;
|
||||
pub use common_dto::ResponseListSuccessDto;
|
||||
pub use common_dto::ResponseSuccessDto;
|
||||
|
||||
// Explicit users exports
|
||||
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;
|
||||
pub use seaorm::common::enums::ResourceEnum;
|
||||
|
||||
// Explicit audit_log exports
|
||||
pub use audit_log::AuditLogSchema;
|
||||
|
||||
// SeaORM entity exports
|
||||
pub use seaorm::*;
|
||||
pub mod audit_log;
|
||||
pub mod common_dto;
|
||||
pub mod error_dto;
|
||||
pub mod permissions;
|
||||
pub mod seaorm;
|
||||
pub mod users;
|
||||
|
||||
pub use common_dto::ErrorDto;
|
||||
pub use common_dto::MessageResponseDto;
|
||||
pub use common_dto::ResponseListSuccessDto;
|
||||
pub use common_dto::ResponseSuccessDto;
|
||||
|
||||
pub use users::RolesDetailItemDto;
|
||||
pub use users::RolesDetailQueryDto;
|
||||
pub use users::UsersDetailQueryDto;
|
||||
|
||||
pub use permissions::PermissionsEnum;
|
||||
pub use permissions::PermissionsItemDto;
|
||||
pub use permissions::PermissionsQueryDto;
|
||||
pub use seaorm::common::enums::ResourceEnum;
|
||||
|
||||
pub use audit_log::AuditLogSchema;
|
||||
|
||||
pub use seaorm::*;
|
||||
|
||||
@@ -1,273 +0,0 @@
|
||||
use std::fmt;
|
||||
use uuid::Uuid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, strum::EnumIter)]
|
||||
pub enum PermissionsEnum {
|
||||
// User permissions
|
||||
ReadListUsers,
|
||||
ReadDetailUsers,
|
||||
CreateUsers,
|
||||
DeleteUsers,
|
||||
UpdateUsers,
|
||||
ActivateUsers,
|
||||
|
||||
// Role permissions
|
||||
ReadListRoles,
|
||||
ReadDetailRoles,
|
||||
CreateRoles,
|
||||
DeleteRoles,
|
||||
UpdateRoles,
|
||||
|
||||
// Permission permissions
|
||||
ReadListPermissions,
|
||||
ReadDetailPermissions,
|
||||
CreatePermissions,
|
||||
DeletePermissions,
|
||||
UpdatePermissions,
|
||||
|
||||
// Administrator permissions
|
||||
ManageAllUsers,
|
||||
ManageAllRoles,
|
||||
ManageAllPermissions,
|
||||
ViewAllSensitiveData,
|
||||
AccessAdminDashboard,
|
||||
Administrator,
|
||||
|
||||
// Gacha permissions
|
||||
CreateGachaClaims,
|
||||
ReadDetailGachaClaims,
|
||||
ReadListGachaItems,
|
||||
ReadDetailGachaItems,
|
||||
CreateGachaItems,
|
||||
DeleteGachaItems,
|
||||
UpdateGachaItems,
|
||||
ReadDetailGachaRolls,
|
||||
CreateGachaRolls,
|
||||
ExecuteGachaRolls,
|
||||
DeleteGachaRolls,
|
||||
|
||||
// Mentor permissions
|
||||
ReadListMentors,
|
||||
ReadDetailMentors,
|
||||
RegisterMentors,
|
||||
ReadOwnMentorProfile,
|
||||
UpdateOwnMentorProfile,
|
||||
ReadOwnMentorStatus,
|
||||
UpdateMentors,
|
||||
VerifyMentors,
|
||||
DeleteMentors,
|
||||
}
|
||||
|
||||
impl fmt::Display for PermissionsEnum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let permission_str = match self {
|
||||
// User permissions
|
||||
PermissionsEnum::ReadListUsers => "Read List Users",
|
||||
PermissionsEnum::ReadDetailUsers => "Read Detail Users",
|
||||
PermissionsEnum::CreateUsers => "Create Users",
|
||||
PermissionsEnum::DeleteUsers => "Delete Users",
|
||||
PermissionsEnum::UpdateUsers => "Update Users",
|
||||
PermissionsEnum::ActivateUsers => "Activate Users",
|
||||
|
||||
// Role permissions
|
||||
PermissionsEnum::ReadListRoles => "Read List Roles",
|
||||
PermissionsEnum::ReadDetailRoles => "Read Detail Roles",
|
||||
PermissionsEnum::CreateRoles => "Create Roles",
|
||||
PermissionsEnum::DeleteRoles => "Delete Roles",
|
||||
PermissionsEnum::UpdateRoles => "Update Roles",
|
||||
|
||||
// Permission permissions
|
||||
PermissionsEnum::ReadListPermissions => "Read List Permissions",
|
||||
PermissionsEnum::ReadDetailPermissions => "Read Detail Permissions",
|
||||
PermissionsEnum::CreatePermissions => "Create Permissions",
|
||||
PermissionsEnum::DeletePermissions => "Delete Permissions",
|
||||
PermissionsEnum::UpdatePermissions => "Update Permissions",
|
||||
|
||||
// Gacha permissions
|
||||
PermissionsEnum::CreateGachaClaims => "Create Gacha Claims",
|
||||
PermissionsEnum::ReadDetailGachaClaims => "Read Detail Gacha Claims",
|
||||
PermissionsEnum::ReadListGachaItems => "Read List Gacha Items",
|
||||
PermissionsEnum::ReadDetailGachaItems => "Read Detail Gacha Items",
|
||||
PermissionsEnum::CreateGachaItems => "Create Gacha Items",
|
||||
PermissionsEnum::DeleteGachaItems => "Delete Gacha Items",
|
||||
PermissionsEnum::UpdateGachaItems => "Update Gacha Items",
|
||||
PermissionsEnum::ReadDetailGachaRolls => "Read Detail Gacha Rolls",
|
||||
PermissionsEnum::CreateGachaRolls => "Create Gacha Rolls",
|
||||
PermissionsEnum::ExecuteGachaRolls => "Execute Gacha Rolls",
|
||||
PermissionsEnum::DeleteGachaRolls => "Delete Gacha Rolls",
|
||||
|
||||
// Mentor permissions
|
||||
PermissionsEnum::ReadListMentors => "Read List Mentors",
|
||||
PermissionsEnum::ReadDetailMentors => "Read Detail Mentors",
|
||||
PermissionsEnum::RegisterMentors => "Register Mentors",
|
||||
PermissionsEnum::ReadOwnMentorProfile => "Read Own Mentor Profile",
|
||||
PermissionsEnum::UpdateOwnMentorProfile => "Update Own Mentor Profile",
|
||||
PermissionsEnum::ReadOwnMentorStatus => "Read Own Mentor Status",
|
||||
PermissionsEnum::UpdateMentors => "Update Mentors",
|
||||
PermissionsEnum::VerifyMentors => "Verify Mentors",
|
||||
PermissionsEnum::DeleteMentors => "Delete Mentors",
|
||||
|
||||
// Administrator permissions
|
||||
PermissionsEnum::ManageAllUsers => "Manage All Users",
|
||||
PermissionsEnum::ManageAllRoles => "Manage All Roles",
|
||||
PermissionsEnum::ManageAllPermissions => "Manage All Permissions",
|
||||
PermissionsEnum::ViewAllSensitiveData => "View All Sensitive Data",
|
||||
PermissionsEnum::AccessAdminDashboard => "Access Admin Dashboard",
|
||||
PermissionsEnum::Administrator => "Administrator",
|
||||
};
|
||||
write!(f, "{permission_str}")
|
||||
}
|
||||
}
|
||||
|
||||
impl PermissionsEnum {
|
||||
pub fn id(&self) -> String {
|
||||
match self {
|
||||
// User permissions
|
||||
PermissionsEnum::ReadListUsers => "7c15e31d-36e2-49f9-97db-138c03fb0cf6".to_string(),
|
||||
PermissionsEnum::ReadDetailUsers => "319ee593-ff0a-4f29-bbaf-9feb3174a3a6".to_string(),
|
||||
PermissionsEnum::CreateUsers => "023e2dfe-93c3-4008-94a8-b5dff403f73b".to_string(),
|
||||
PermissionsEnum::DeleteUsers => "96df0689-2ae9-4894-bf00-837c19415e5c".to_string(),
|
||||
PermissionsEnum::UpdateUsers => "98b3dc4c-0124-461f-afcd-166637c5e6e8".to_string(),
|
||||
PermissionsEnum::ActivateUsers => "4da8b434-89f9-4d91-85ae-eebd63cdbeda".to_string(),
|
||||
|
||||
// Role permissions
|
||||
PermissionsEnum::ReadListRoles => "9164ca6e-c7e3-4238-a15f-f36ab9577e7e".to_string(),
|
||||
PermissionsEnum::ReadDetailRoles => "73888d18-b3e9-4f62-95a5-ba2c0d69fccb".to_string(),
|
||||
PermissionsEnum::CreateRoles => "319ee593-ff0a-4f29-bbaf-9feb3174a3a2".to_string(),
|
||||
PermissionsEnum::DeleteRoles => "35b0d992-65c8-4b62-b030-e6e0320e4048".to_string(),
|
||||
PermissionsEnum::UpdateRoles => "a00d5608-4c48-4542-845c-dfe004687022".to_string(),
|
||||
|
||||
// Permission permissions
|
||||
PermissionsEnum::ReadListPermissions => "8195eeb8-e64f-4172-aa57-596492c84a72".to_string(),
|
||||
PermissionsEnum::ReadDetailPermissions => "dad435cf-042c-41bd-a946-cea61ed2ffbc".to_string(),
|
||||
PermissionsEnum::CreatePermissions => "0269ed71-0ae0-4c43-ad29-e3d861d8f9a0".to_string(),
|
||||
PermissionsEnum::DeletePermissions => "b2dc3928-86ba-4c59-a03d-0b57d5183ebc".to_string(),
|
||||
PermissionsEnum::UpdatePermissions => "299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b".to_string(),
|
||||
|
||||
// Gacha permissions
|
||||
PermissionsEnum::CreateGachaClaims => "f41d53ce-4f88-4bb6-b9b4-5e3a8c38d962".to_string(),
|
||||
PermissionsEnum::ReadDetailGachaClaims => "c1c3d6c2-19fb-4b70-b58c-c19f2e8cfc79".to_string(),
|
||||
PermissionsEnum::ReadListGachaItems => "fa6eb842-0a61-40c2-9c24-b226ad975037".to_string(),
|
||||
PermissionsEnum::ReadDetailGachaItems => "9c7857d7-b5ae-4688-923d-ef5572e9bc8b".to_string(),
|
||||
PermissionsEnum::CreateGachaItems => "cf063be1-4d71-489e-b9fb-1c08c65f396c".to_string(),
|
||||
PermissionsEnum::DeleteGachaItems => "46f8c6cf-ea0c-4c90-860c-69e2e65f7eb1".to_string(),
|
||||
PermissionsEnum::UpdateGachaItems => "2d0cf4ae-56ae-4714-a12e-655cfc3d9eb2".to_string(),
|
||||
PermissionsEnum::ReadDetailGachaRolls => "53d6483a-04cd-4667-8792-2d0cc8e2d343".to_string(),
|
||||
PermissionsEnum::CreateGachaRolls => "18e36c63-fcb7-4877-b911-c5aa611e878f".to_string(),
|
||||
PermissionsEnum::ExecuteGachaRolls => "14c6a1cd-5c63-4643-89b5-b1a5f9920cc0".to_string(),
|
||||
PermissionsEnum::DeleteGachaRolls => "12345678-ABCD-EFAB-CDEF-0123456789AB".to_string(),
|
||||
|
||||
// Mentor permissions
|
||||
PermissionsEnum::ReadListMentors => "a1b2c3d4-5e6f-7890-abcd-ef1234567890".to_string(),
|
||||
PermissionsEnum::ReadDetailMentors => "b2c3d4e5-6f78-9012-bcde-f23456789012".to_string(),
|
||||
PermissionsEnum::RegisterMentors => "c3d4e5f6-7890-1234-cdef-345678901234".to_string(),
|
||||
PermissionsEnum::ReadOwnMentorProfile => "d4e5f6a7-8901-2345-def0-456789012345".to_string(),
|
||||
PermissionsEnum::UpdateOwnMentorProfile => "e5f6a7b8-9012-3456-ef01-567890123456".to_string(),
|
||||
PermissionsEnum::ReadOwnMentorStatus => "f6a7b8c9-0123-4567-f012-678901234567".to_string(),
|
||||
PermissionsEnum::UpdateMentors => "a7b8c9d0-1234-5678-0123-789012345678".to_string(),
|
||||
PermissionsEnum::VerifyMentors => "b8c9d0e1-2345-6789-1234-890123456789".to_string(),
|
||||
PermissionsEnum::DeleteMentors => "c9d0e1f2-3456-7890-2345-901234567890".to_string(),
|
||||
|
||||
// Administrator permissions
|
||||
PermissionsEnum::ManageAllUsers => "d0e1f2a3-4567-8901-2345-0123456789ab".to_string(),
|
||||
PermissionsEnum::ManageAllRoles => "e1f2a3b4-5678-9012-3456-1234567890ab".to_string(),
|
||||
PermissionsEnum::ManageAllPermissions => "f2a3b4c5-6789-0123-4567-2345678901ab".to_string(),
|
||||
PermissionsEnum::ViewAllSensitiveData => "b4c5d6e7-8901-2345-6789-4567890123ab".to_string(),
|
||||
PermissionsEnum::AccessAdminDashboard => "c5d6e7f8-9012-3456-7890-5678901234ab".to_string(),
|
||||
PermissionsEnum::Administrator => "d6e7f8a9-0123-4567-8901-6789012345ab".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a new unique ID for a permission
|
||||
pub fn generate_id() -> String {
|
||||
Uuid::new_v4().to_string()
|
||||
}
|
||||
|
||||
/// Get all permissions as a vector
|
||||
pub fn all() -> Vec<PermissionsEnum> {
|
||||
vec![
|
||||
// User permissions
|
||||
PermissionsEnum::ReadListUsers,
|
||||
PermissionsEnum::ReadDetailUsers,
|
||||
PermissionsEnum::CreateUsers,
|
||||
PermissionsEnum::DeleteUsers,
|
||||
PermissionsEnum::UpdateUsers,
|
||||
PermissionsEnum::ActivateUsers,
|
||||
|
||||
// Role permissions
|
||||
PermissionsEnum::ReadListRoles,
|
||||
PermissionsEnum::ReadDetailRoles,
|
||||
PermissionsEnum::CreateRoles,
|
||||
PermissionsEnum::DeleteRoles,
|
||||
PermissionsEnum::UpdateRoles,
|
||||
|
||||
// Permission permissions
|
||||
PermissionsEnum::ReadListPermissions,
|
||||
PermissionsEnum::ReadDetailPermissions,
|
||||
PermissionsEnum::CreatePermissions,
|
||||
PermissionsEnum::DeletePermissions,
|
||||
PermissionsEnum::UpdatePermissions,
|
||||
|
||||
// Gacha permissions
|
||||
PermissionsEnum::CreateGachaClaims,
|
||||
PermissionsEnum::ReadDetailGachaClaims,
|
||||
PermissionsEnum::ReadListGachaItems,
|
||||
PermissionsEnum::ReadDetailGachaItems,
|
||||
PermissionsEnum::CreateGachaItems,
|
||||
PermissionsEnum::DeleteGachaItems,
|
||||
PermissionsEnum::UpdateGachaItems,
|
||||
PermissionsEnum::ReadDetailGachaRolls,
|
||||
PermissionsEnum::CreateGachaRolls,
|
||||
PermissionsEnum::ExecuteGachaRolls,
|
||||
PermissionsEnum::DeleteGachaRolls,
|
||||
|
||||
// Mentor permissions
|
||||
PermissionsEnum::ReadListMentors,
|
||||
PermissionsEnum::ReadDetailMentors,
|
||||
PermissionsEnum::RegisterMentors,
|
||||
PermissionsEnum::ReadOwnMentorProfile,
|
||||
PermissionsEnum::UpdateOwnMentorProfile,
|
||||
PermissionsEnum::ReadOwnMentorStatus,
|
||||
PermissionsEnum::UpdateMentors,
|
||||
PermissionsEnum::VerifyMentors,
|
||||
PermissionsEnum::DeleteMentors,
|
||||
|
||||
// Administrator permissions
|
||||
PermissionsEnum::ManageAllUsers,
|
||||
PermissionsEnum::ManageAllRoles,
|
||||
PermissionsEnum::ManageAllPermissions,
|
||||
PermissionsEnum::ViewAllSensitiveData,
|
||||
PermissionsEnum::AccessAdminDashboard,
|
||||
PermissionsEnum::Administrator,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct PermissionsItemDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
impl PermissionsItemDto {
|
||||
pub fn from(dto: &PermissionsQueryDto) -> Self {
|
||||
Self {
|
||||
id: dto.id.clone().unwrap_or_default(),
|
||||
name: dto.name.clone().unwrap_or_default(),
|
||||
created_at: dto.created_at.clone(),
|
||||
updated_at: dto.updated_at.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PermissionsQueryDto {
|
||||
pub id: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use utoipa::ToSchema;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, strum::EnumIter)]
|
||||
pub enum PermissionsEnum {
|
||||
ReadListUsers,
|
||||
ReadDetailUsers,
|
||||
CreateUsers,
|
||||
DeleteUsers,
|
||||
UpdateUsers,
|
||||
ActivateUsers,
|
||||
|
||||
ReadListRoles,
|
||||
ReadDetailRoles,
|
||||
CreateRoles,
|
||||
DeleteRoles,
|
||||
UpdateRoles,
|
||||
|
||||
ReadListPermissions,
|
||||
ReadDetailPermissions,
|
||||
CreatePermissions,
|
||||
DeletePermissions,
|
||||
UpdatePermissions,
|
||||
|
||||
ManageAllUsers,
|
||||
ManageAllRoles,
|
||||
ManageAllPermissions,
|
||||
ViewAllSensitiveData,
|
||||
AccessAdminDashboard,
|
||||
Administrator,
|
||||
|
||||
CreateGachaClaims,
|
||||
ReadDetailGachaClaims,
|
||||
ReadListGachaItems,
|
||||
ReadDetailGachaItems,
|
||||
CreateGachaItems,
|
||||
DeleteGachaItems,
|
||||
UpdateGachaItems,
|
||||
ReadDetailGachaRolls,
|
||||
CreateGachaRolls,
|
||||
ExecuteGachaRolls,
|
||||
DeleteGachaRolls,
|
||||
|
||||
ReadListMentors,
|
||||
ReadDetailMentors,
|
||||
RegisterMentors,
|
||||
ReadOwnMentorProfile,
|
||||
UpdateOwnMentorProfile,
|
||||
ReadOwnMentorStatus,
|
||||
UpdateMentors,
|
||||
VerifyMentors,
|
||||
DeleteMentors,
|
||||
}
|
||||
|
||||
impl fmt::Display for PermissionsEnum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let permission_str = match self {
|
||||
PermissionsEnum::ReadListUsers => "Read List Users",
|
||||
PermissionsEnum::ReadDetailUsers => "Read Detail Users",
|
||||
PermissionsEnum::CreateUsers => "Create Users",
|
||||
PermissionsEnum::DeleteUsers => "Delete Users",
|
||||
PermissionsEnum::UpdateUsers => "Update Users",
|
||||
PermissionsEnum::ActivateUsers => "Activate Users",
|
||||
|
||||
PermissionsEnum::ReadListRoles => "Read List Roles",
|
||||
PermissionsEnum::ReadDetailRoles => "Read Detail Roles",
|
||||
PermissionsEnum::CreateRoles => "Create Roles",
|
||||
PermissionsEnum::DeleteRoles => "Delete Roles",
|
||||
PermissionsEnum::UpdateRoles => "Update Roles",
|
||||
|
||||
PermissionsEnum::ReadListPermissions => "Read List Permissions",
|
||||
PermissionsEnum::ReadDetailPermissions => "Read Detail Permissions",
|
||||
PermissionsEnum::CreatePermissions => "Create Permissions",
|
||||
PermissionsEnum::DeletePermissions => "Delete Permissions",
|
||||
PermissionsEnum::UpdatePermissions => "Update Permissions",
|
||||
|
||||
PermissionsEnum::CreateGachaClaims => "Create Gacha Claims",
|
||||
PermissionsEnum::ReadDetailGachaClaims => "Read Detail Gacha Claims",
|
||||
PermissionsEnum::ReadListGachaItems => "Read List Gacha Items",
|
||||
PermissionsEnum::ReadDetailGachaItems => "Read Detail Gacha Items",
|
||||
PermissionsEnum::CreateGachaItems => "Create Gacha Items",
|
||||
PermissionsEnum::DeleteGachaItems => "Delete Gacha Items",
|
||||
PermissionsEnum::UpdateGachaItems => "Update Gacha Items",
|
||||
PermissionsEnum::ReadDetailGachaRolls => "Read Detail Gacha Rolls",
|
||||
PermissionsEnum::CreateGachaRolls => "Create Gacha Rolls",
|
||||
PermissionsEnum::ExecuteGachaRolls => "Execute Gacha Rolls",
|
||||
PermissionsEnum::DeleteGachaRolls => "Delete Gacha Rolls",
|
||||
|
||||
PermissionsEnum::ReadListMentors => "Read List Mentors",
|
||||
PermissionsEnum::ReadDetailMentors => "Read Detail Mentors",
|
||||
PermissionsEnum::RegisterMentors => "Register Mentors",
|
||||
PermissionsEnum::ReadOwnMentorProfile => "Read Own Mentor Profile",
|
||||
PermissionsEnum::UpdateOwnMentorProfile => "Update Own Mentor Profile",
|
||||
PermissionsEnum::ReadOwnMentorStatus => "Read Own Mentor Status",
|
||||
PermissionsEnum::UpdateMentors => "Update Mentors",
|
||||
PermissionsEnum::VerifyMentors => "Verify Mentors",
|
||||
PermissionsEnum::DeleteMentors => "Delete Mentors",
|
||||
|
||||
PermissionsEnum::ManageAllUsers => "Manage All Users",
|
||||
PermissionsEnum::ManageAllRoles => "Manage All Roles",
|
||||
PermissionsEnum::ManageAllPermissions => "Manage All Permissions",
|
||||
PermissionsEnum::ViewAllSensitiveData => "View All Sensitive Data",
|
||||
PermissionsEnum::AccessAdminDashboard => "Access Admin Dashboard",
|
||||
PermissionsEnum::Administrator => "Administrator",
|
||||
};
|
||||
write!(f, "{permission_str}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct PermissionsItemDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
impl PermissionsItemDto {
|
||||
pub fn from(dto: &PermissionsQueryDto) -> Self {
|
||||
Self {
|
||||
id: dto.id.clone().unwrap_or_default(),
|
||||
name: dto.name.clone().unwrap_or_default(),
|
||||
created_at: dto.created_at.clone(),
|
||||
updated_at: dto.updated_at.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PermissionsQueryDto {
|
||||
pub id: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
impl PermissionsEnum {
|
||||
pub fn generate_id() -> String {
|
||||
Uuid::new_v4().to_string()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
use super::definitions::PermissionsEnum;
|
||||
|
||||
impl PermissionsEnum {
|
||||
pub fn id(&self) -> String {
|
||||
match self {
|
||||
PermissionsEnum::ReadListUsers => {
|
||||
"7c15e31d-36e2-49f9-97db-138c03fb0cf6".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailUsers => {
|
||||
"319ee593-ff0a-4f29-bbaf-9feb3174a3a6".to_string()
|
||||
}
|
||||
PermissionsEnum::CreateUsers => {
|
||||
"023e2dfe-93c3-4008-94a8-b5dff403f73b".to_string()
|
||||
}
|
||||
PermissionsEnum::DeleteUsers => {
|
||||
"96df0689-2ae9-4894-bf00-837c19415e5c".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdateUsers => {
|
||||
"98b3dc4c-0124-461f-afcd-166637c5e6e8".to_string()
|
||||
}
|
||||
PermissionsEnum::ActivateUsers => {
|
||||
"4da8b434-89f9-4d91-85ae-eebd63cdbeda".to_string()
|
||||
}
|
||||
|
||||
PermissionsEnum::ReadListRoles => {
|
||||
"9164ca6e-c7e3-4238-a15f-f36ab9577e7e".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailRoles => {
|
||||
"73888d18-b3e9-4f62-95a5-ba2c0d69fccb".to_string()
|
||||
}
|
||||
PermissionsEnum::CreateRoles => {
|
||||
"319ee593-ff0a-4f29-bbaf-9feb3174a3a2".to_string()
|
||||
}
|
||||
PermissionsEnum::DeleteRoles => {
|
||||
"35b0d992-65c8-4b62-b030-e6e0320e4048".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdateRoles => {
|
||||
"a00d5608-4c48-4542-845c-dfe004687022".to_string()
|
||||
}
|
||||
|
||||
PermissionsEnum::ReadListPermissions => {
|
||||
"8195eeb8-e64f-4172-aa57-596492c84a72".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailPermissions => {
|
||||
"dad435cf-042c-41bd-a946-cea61ed2ffbc".to_string()
|
||||
}
|
||||
PermissionsEnum::CreatePermissions => {
|
||||
"0269ed71-0ae0-4c43-ad29-e3d861d8f9a0".to_string()
|
||||
}
|
||||
PermissionsEnum::DeletePermissions => {
|
||||
"b2dc3928-86ba-4c59-a03d-0b57d5183ebc".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdatePermissions => {
|
||||
"299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b".to_string()
|
||||
}
|
||||
|
||||
PermissionsEnum::CreateGachaClaims => {
|
||||
"f41d53ce-4f88-4bb6-b9b4-5e3a8c38d962".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailGachaClaims => {
|
||||
"c1c3d6c2-19fb-4b70-b58c-c19f2e8cfc79".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadListGachaItems => {
|
||||
"fa6eb842-0a61-40c2-9c24-b226ad975037".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailGachaItems => {
|
||||
"9c7857d7-b5ae-4688-923d-ef5572e9bc8b".to_string()
|
||||
}
|
||||
PermissionsEnum::CreateGachaItems => {
|
||||
"cf063be1-4d71-489e-b9fb-1c08c65f396c".to_string()
|
||||
}
|
||||
PermissionsEnum::DeleteGachaItems => {
|
||||
"46f8c6cf-ea0c-4c90-860c-69e2e65f7eb1".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdateGachaItems => {
|
||||
"2d0cf4ae-56ae-4714-a12e-655cfc3d9eb2".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailGachaRolls => {
|
||||
"53d6483a-04cd-4667-8792-2d0cc8e2d343".to_string()
|
||||
}
|
||||
PermissionsEnum::CreateGachaRolls => {
|
||||
"18e36c63-fcb7-4877-b911-c5aa611e878f".to_string()
|
||||
}
|
||||
PermissionsEnum::ExecuteGachaRolls => {
|
||||
"14c6a1cd-5c63-4643-89b5-b1a5f9920cc0".to_string()
|
||||
}
|
||||
PermissionsEnum::DeleteGachaRolls => {
|
||||
"12345678-ABCD-EFAB-CDEF-0123456789AB".to_string()
|
||||
}
|
||||
|
||||
PermissionsEnum::ReadListMentors => {
|
||||
"a1b2c3d4-5e6f-7890-abcd-ef1234567890".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadDetailMentors => {
|
||||
"b2c3d4e5-6f78-9012-bcde-f23456789012".to_string()
|
||||
}
|
||||
PermissionsEnum::RegisterMentors => {
|
||||
"c3d4e5f6-7890-1234-cdef-345678901234".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadOwnMentorProfile => {
|
||||
"d4e5f6a7-8901-2345-def0-456789012345".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdateOwnMentorProfile => {
|
||||
"e5f6a7b8-9012-3456-ef01-567890123456".to_string()
|
||||
}
|
||||
PermissionsEnum::ReadOwnMentorStatus => {
|
||||
"f6a7b8c9-0123-4567-f012-678901234567".to_string()
|
||||
}
|
||||
PermissionsEnum::UpdateMentors => {
|
||||
"a7b8c9d0-1234-5678-0123-789012345678".to_string()
|
||||
}
|
||||
PermissionsEnum::VerifyMentors => {
|
||||
"b8c9d0e1-2345-6789-1234-890123456789".to_string()
|
||||
}
|
||||
PermissionsEnum::DeleteMentors => {
|
||||
"c9d0e1f2-3456-7890-2345-901234567890".to_string()
|
||||
}
|
||||
|
||||
PermissionsEnum::ManageAllUsers => {
|
||||
"d0e1f2a3-4567-8901-2345-0123456789ab".to_string()
|
||||
}
|
||||
PermissionsEnum::ManageAllRoles => {
|
||||
"e1f2a3b4-5678-9012-3456-1234567890ab".to_string()
|
||||
}
|
||||
PermissionsEnum::ManageAllPermissions => {
|
||||
"f2a3b4c5-6789-0123-4567-2345678901ab".to_string()
|
||||
}
|
||||
PermissionsEnum::ViewAllSensitiveData => {
|
||||
"b4c5d6e7-8901-2345-6789-4567890123ab".to_string()
|
||||
}
|
||||
PermissionsEnum::AccessAdminDashboard => {
|
||||
"c5d6e7f8-9012-3456-7890-5678901234ab".to_string()
|
||||
}
|
||||
PermissionsEnum::Administrator => {
|
||||
"d6e7f8a9-0123-4567-8901-6789012345ab".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all() -> Vec<PermissionsEnum> {
|
||||
vec![
|
||||
PermissionsEnum::ReadListUsers,
|
||||
PermissionsEnum::ReadDetailUsers,
|
||||
PermissionsEnum::CreateUsers,
|
||||
PermissionsEnum::DeleteUsers,
|
||||
PermissionsEnum::UpdateUsers,
|
||||
PermissionsEnum::ActivateUsers,
|
||||
PermissionsEnum::ReadListRoles,
|
||||
PermissionsEnum::ReadDetailRoles,
|
||||
PermissionsEnum::CreateRoles,
|
||||
PermissionsEnum::DeleteRoles,
|
||||
PermissionsEnum::UpdateRoles,
|
||||
PermissionsEnum::ReadListPermissions,
|
||||
PermissionsEnum::ReadDetailPermissions,
|
||||
PermissionsEnum::CreatePermissions,
|
||||
PermissionsEnum::DeletePermissions,
|
||||
PermissionsEnum::UpdatePermissions,
|
||||
PermissionsEnum::CreateGachaClaims,
|
||||
PermissionsEnum::ReadDetailGachaClaims,
|
||||
PermissionsEnum::ReadListGachaItems,
|
||||
PermissionsEnum::ReadDetailGachaItems,
|
||||
PermissionsEnum::CreateGachaItems,
|
||||
PermissionsEnum::DeleteGachaItems,
|
||||
PermissionsEnum::UpdateGachaItems,
|
||||
PermissionsEnum::ReadDetailGachaRolls,
|
||||
PermissionsEnum::CreateGachaRolls,
|
||||
PermissionsEnum::ExecuteGachaRolls,
|
||||
PermissionsEnum::DeleteGachaRolls,
|
||||
PermissionsEnum::ReadListMentors,
|
||||
PermissionsEnum::ReadDetailMentors,
|
||||
PermissionsEnum::RegisterMentors,
|
||||
PermissionsEnum::ReadOwnMentorProfile,
|
||||
PermissionsEnum::UpdateOwnMentorProfile,
|
||||
PermissionsEnum::ReadOwnMentorStatus,
|
||||
PermissionsEnum::UpdateMentors,
|
||||
PermissionsEnum::VerifyMentors,
|
||||
PermissionsEnum::DeleteMentors,
|
||||
PermissionsEnum::ManageAllUsers,
|
||||
PermissionsEnum::ManageAllRoles,
|
||||
PermissionsEnum::ManageAllPermissions,
|
||||
PermissionsEnum::ViewAllSensitiveData,
|
||||
PermissionsEnum::AccessAdminDashboard,
|
||||
PermissionsEnum::Administrator,
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod definitions;
|
||||
pub mod mappings;
|
||||
|
||||
pub use definitions::{PermissionsEnum, PermissionsItemDto, PermissionsQueryDto};
|
||||
@@ -1,298 +1,198 @@
|
||||
//! SeaORM entity for Mentors table
|
||||
//! Corresponding to ResourceEnum::Mentors
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, imphnen_macros::Builder)]
|
||||
#[sea_orm(table_name = "app_mentors")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub industries: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub expertise: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub languages: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub current_company: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub current_role: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub years_of_experience: Option<i32>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub topics_of_interest: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub preferred_mentee_level: Option<String>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub preferred_mentoring_formats: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub availability_commitment: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub mentoring_rate: Option<f64>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub status: Option<String>,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(belongs_to = "super::users::Entity", from = "Column::UserId", to = "super::users::Column::Id")]
|
||||
User,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for Mentor creation
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct MentorBuilder {
|
||||
user_id: Option<Uuid>,
|
||||
industries: Option<Vec<String>>,
|
||||
expertise: Option<Vec<String>>,
|
||||
languages: Option<Vec<String>>,
|
||||
current_company: Option<String>,
|
||||
current_role: Option<String>,
|
||||
years_of_experience: Option<i32>,
|
||||
topics_of_interest: Option<Vec<String>>,
|
||||
preferred_mentee_level: Option<String>,
|
||||
preferred_mentoring_formats: Option<Vec<String>>,
|
||||
availability_commitment: Option<String>,
|
||||
mentoring_rate: Option<f64>,
|
||||
status: Option<String>,
|
||||
is_deleted: Option<bool>,
|
||||
}
|
||||
|
||||
impl MentorBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn industries(mut self, industries: Vec<String>) -> Self {
|
||||
self.industries = Some(industries);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expertise(mut self, expertise: Vec<String>) -> Self {
|
||||
self.expertise = Some(expertise);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn languages(mut self, languages: Vec<String>) -> Self {
|
||||
self.languages = Some(languages);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_company(mut self, current_company: String) -> Self {
|
||||
self.current_company = Some(current_company);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_role(mut self, current_role: String) -> Self {
|
||||
self.current_role = Some(current_role);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn years_of_experience(mut self, years_of_experience: i32) -> Self {
|
||||
self.years_of_experience = Some(years_of_experience);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn topics_of_interest(mut self, topics_of_interest: Vec<String>) -> Self {
|
||||
self.topics_of_interest = Some(topics_of_interest);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn preferred_mentee_level(mut self, preferred_mentee_level: String) -> Self {
|
||||
self.preferred_mentee_level = Some(preferred_mentee_level);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn preferred_mentoring_formats(mut self, preferred_mentoring_formats: Vec<String>) -> Self {
|
||||
self.preferred_mentoring_formats = Some(preferred_mentoring_formats);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn availability_commitment(mut self, availability_commitment: String) -> Self {
|
||||
self.availability_commitment = Some(availability_commitment);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mentoring_rate(mut self, mentoring_rate: f64) -> Self {
|
||||
self.mentoring_rate = Some(mentoring_rate);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn status(mut self, status: String) -> Self {
|
||||
self.status = Some(status);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_deleted(mut self, is_deleted: bool) -> Self {
|
||||
self.is_deleted = Some(is_deleted);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(user_id) = self.user_id {
|
||||
active_model.user_id = Set(user_id);
|
||||
} else {
|
||||
return Err("User ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(industries) = self.industries {
|
||||
active_model.industries = Set(Some(serde_json::to_value(industries).map_err(|e| format!("Failed to serialize industries: {}", e))?));
|
||||
}
|
||||
|
||||
if let Some(expertise) = self.expertise {
|
||||
active_model.expertise = Set(Some(serde_json::to_value(expertise).map_err(|e| format!("Failed to serialize expertise: {}", e))?));
|
||||
}
|
||||
|
||||
if let Some(languages) = self.languages {
|
||||
active_model.languages = Set(Some(serde_json::to_value(languages).map_err(|e| format!("Failed to serialize languages: {}", e))?));
|
||||
}
|
||||
|
||||
if let Some(current_company) = self.current_company {
|
||||
active_model.current_company = Set(Some(current_company));
|
||||
}
|
||||
|
||||
if let Some(current_role) = self.current_role {
|
||||
active_model.current_role = Set(Some(current_role));
|
||||
}
|
||||
|
||||
if let Some(years_of_experience) = self.years_of_experience {
|
||||
active_model.years_of_experience = Set(Some(years_of_experience));
|
||||
}
|
||||
|
||||
if let Some(topics_of_interest) = self.topics_of_interest {
|
||||
active_model.topics_of_interest = Set(Some(serde_json::to_value(topics_of_interest).map_err(|e| format!("Failed to serialize topics_of_interest: {}", e))?));
|
||||
}
|
||||
|
||||
if let Some(preferred_mentee_level) = self.preferred_mentee_level {
|
||||
active_model.preferred_mentee_level = Set(Some(preferred_mentee_level));
|
||||
}
|
||||
|
||||
if let Some(preferred_mentoring_formats) = self.preferred_mentoring_formats {
|
||||
active_model.preferred_mentoring_formats = Set(Some(serde_json::to_value(preferred_mentoring_formats).map_err(|e| format!("Failed to serialize preferred_mentoring_formats: {}", e))?));
|
||||
}
|
||||
|
||||
if let Some(availability_commitment) = self.availability_commitment {
|
||||
active_model.availability_commitment = Set(Some(availability_commitment));
|
||||
}
|
||||
|
||||
if let Some(mentoring_rate) = self.mentoring_rate {
|
||||
active_model.mentoring_rate = Set(Some(mentoring_rate));
|
||||
}
|
||||
|
||||
if let Some(status) = self.status {
|
||||
active_model.status = Set(Some(status));
|
||||
}
|
||||
|
||||
if let Some(is_deleted) = self.is_deleted {
|
||||
active_model.is_deleted = Set(is_deleted);
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::seaorm::common::utils::generate_uuid;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_mentor_model_creation() {
|
||||
let uid = generate_uuid();
|
||||
let mentor = MentorBuilder::new()
|
||||
.user_id(uid)
|
||||
.industries(vec!["Technology".to_string(), "Finance".to_string()])
|
||||
.expertise(vec!["Blockchain".to_string(), "AI".to_string()])
|
||||
.languages(vec!["English".to_string(), "Spanish".to_string()])
|
||||
.current_company("Tech Corp".to_string())
|
||||
.current_role("Senior Engineer".to_string())
|
||||
.years_of_experience(10)
|
||||
.topics_of_interest(vec!["Web3".to_string(), "Machine Learning".to_string()])
|
||||
.preferred_mentee_level("Intermediate".to_string())
|
||||
.preferred_mentoring_formats(vec!["1:1".to_string(), "Group".to_string()])
|
||||
.availability_commitment("Weekly".to_string())
|
||||
.mentoring_rate(150.0)
|
||||
.status("active".to_string())
|
||||
.build();
|
||||
|
||||
assert!(mentor.is_ok());
|
||||
let mentor_model = mentor.unwrap();
|
||||
assert_eq!(mentor_model.user_id, Set(uid));
|
||||
assert_eq!(mentor_model.industries, Set(Some(json!(["Technology", "Finance"]))));
|
||||
assert_eq!(mentor_model.expertise, Set(Some(json!(["Blockchain", "AI"]))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mentor_model_missing_required_fields() {
|
||||
let mentor = MentorBuilder::new()
|
||||
// Missing user_id
|
||||
.industries(vec!["Technology".to_string()])
|
||||
.build();
|
||||
|
||||
assert!(mentor.is_err());
|
||||
assert_eq!(mentor.unwrap_err(), "User ID is required");
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
DeriveEntityModel,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
imphnen_macros::Builder,
|
||||
)]
|
||||
#[sea_orm(table_name = "app_mentors")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub industries: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub expertise: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub languages: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub current_company: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub current_role: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub years_of_experience: Option<i32>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub topics_of_interest: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub preferred_mentee_level: Option<String>,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub preferred_mentoring_formats: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub availability_commitment: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub mentoring_rate: Option<f64>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub status: Option<String>,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
User,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct MentorBuilder {
|
||||
pub user_id: Option<Uuid>,
|
||||
pub industries: Option<Vec<String>>,
|
||||
pub expertise: Option<Vec<String>>,
|
||||
pub languages: Option<Vec<String>>,
|
||||
pub current_company: Option<String>,
|
||||
pub current_role: Option<String>,
|
||||
pub years_of_experience: Option<i32>,
|
||||
pub topics_of_interest: Option<Vec<String>>,
|
||||
pub preferred_mentee_level: Option<String>,
|
||||
pub preferred_mentoring_formats: Option<Vec<String>>,
|
||||
pub availability_commitment: Option<String>,
|
||||
pub mentoring_rate: Option<f64>,
|
||||
pub status: Option<String>,
|
||||
pub is_deleted: Option<bool>,
|
||||
}
|
||||
|
||||
impl MentorBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn industries(mut self, industries: Vec<String>) -> Self {
|
||||
self.industries = Some(industries);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expertise(mut self, expertise: Vec<String>) -> Self {
|
||||
self.expertise = Some(expertise);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn languages(mut self, languages: Vec<String>) -> Self {
|
||||
self.languages = Some(languages);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_company(mut self, current_company: String) -> Self {
|
||||
self.current_company = Some(current_company);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn current_role(mut self, current_role: String) -> Self {
|
||||
self.current_role = Some(current_role);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn years_of_experience(mut self, years_of_experience: i32) -> Self {
|
||||
self.years_of_experience = Some(years_of_experience);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn topics_of_interest(mut self, topics_of_interest: Vec<String>) -> Self {
|
||||
self.topics_of_interest = Some(topics_of_interest);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn preferred_mentee_level(mut self, preferred_mentee_level: String) -> Self {
|
||||
self.preferred_mentee_level = Some(preferred_mentee_level);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn preferred_mentoring_formats(
|
||||
mut self,
|
||||
preferred_mentoring_formats: Vec<String>,
|
||||
) -> Self {
|
||||
self.preferred_mentoring_formats = Some(preferred_mentoring_formats);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn availability_commitment(mut self, availability_commitment: String) -> Self {
|
||||
self.availability_commitment = Some(availability_commitment);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mentoring_rate(mut self, mentoring_rate: f64) -> Self {
|
||||
self.mentoring_rate = Some(mentoring_rate);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn status(mut self, status: String) -> Self {
|
||||
self.status = Some(status);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_deleted(mut self, is_deleted: bool) -> Self {
|
||||
self.is_deleted = Some(is_deleted);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
use super::mentors::{ActiveModel, MentorBuilder};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
|
||||
impl MentorBuilder {
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(user_id) = self.user_id {
|
||||
active_model.user_id = Set(user_id);
|
||||
} else {
|
||||
return Err("User ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(industries) = self.industries {
|
||||
active_model.industries =
|
||||
Set(Some(serde_json::to_value(industries).map_err(|e| {
|
||||
format!("Failed to serialize industries: {}", e)
|
||||
})?));
|
||||
}
|
||||
|
||||
if let Some(expertise) = self.expertise {
|
||||
active_model.expertise =
|
||||
Set(Some(serde_json::to_value(expertise).map_err(|e| {
|
||||
format!("Failed to serialize expertise: {}", e)
|
||||
})?));
|
||||
}
|
||||
|
||||
if let Some(languages) = self.languages {
|
||||
active_model.languages =
|
||||
Set(Some(serde_json::to_value(languages).map_err(|e| {
|
||||
format!("Failed to serialize languages: {}", e)
|
||||
})?));
|
||||
}
|
||||
|
||||
if let Some(current_company) = self.current_company {
|
||||
active_model.current_company = Set(Some(current_company));
|
||||
}
|
||||
|
||||
if let Some(current_role) = self.current_role {
|
||||
active_model.current_role = Set(Some(current_role));
|
||||
}
|
||||
|
||||
if let Some(years_of_experience) = self.years_of_experience {
|
||||
active_model.years_of_experience = Set(Some(years_of_experience));
|
||||
}
|
||||
|
||||
if let Some(topics_of_interest) = self.topics_of_interest {
|
||||
active_model.topics_of_interest = Set(Some(
|
||||
serde_json::to_value(topics_of_interest)
|
||||
.map_err(|e| format!("Failed to serialize topics_of_interest: {}", e))?,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(preferred_mentee_level) = self.preferred_mentee_level {
|
||||
active_model.preferred_mentee_level = Set(Some(preferred_mentee_level));
|
||||
}
|
||||
|
||||
if let Some(preferred_mentoring_formats) = self.preferred_mentoring_formats {
|
||||
active_model.preferred_mentoring_formats = Set(Some(
|
||||
serde_json::to_value(preferred_mentoring_formats).map_err(|e| {
|
||||
format!("Failed to serialize preferred_mentoring_formats: {}", e)
|
||||
})?,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(availability_commitment) = self.availability_commitment {
|
||||
active_model.availability_commitment = Set(Some(availability_commitment));
|
||||
}
|
||||
|
||||
if let Some(mentoring_rate) = self.mentoring_rate {
|
||||
active_model.mentoring_rate = Set(Some(mentoring_rate));
|
||||
}
|
||||
|
||||
if let Some(status) = self.status {
|
||||
active_model.status = Set(Some(status));
|
||||
}
|
||||
|
||||
if let Some(is_deleted) = self.is_deleted {
|
||||
active_model.is_deleted = Set(is_deleted);
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod users;
|
||||
pub mod roles;
|
||||
pub mod permissions;
|
||||
pub mod roles_permissions;
|
||||
pub mod mentors;
|
||||
pub mod sessions;
|
||||
|
||||
pub mod mentors;
|
||||
pub mod mentors_queries;
|
||||
pub mod permissions;
|
||||
pub mod roles;
|
||||
pub mod roles_permissions;
|
||||
pub mod sessions;
|
||||
pub mod users;
|
||||
|
||||
@@ -1,60 +1,55 @@
|
||||
//! SeaORM entity for Permissions table
|
||||
//! Corresponding to ResourceEnum::Permissions
|
||||
//! Represents system permissions
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null, default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::roles_permissions::Entity")]
|
||||
RolesPermissions,
|
||||
}
|
||||
|
||||
impl Related<super::roles_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::RolesPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Entity {
|
||||
pub fn find_by_id(id: Uuid) -> Select<Entity> {
|
||||
Self::find().filter(Column::Id.eq(id))
|
||||
}
|
||||
|
||||
pub fn find_by_name(name: &str) -> Select<Entity> {
|
||||
Self::find().filter(Column::Name.eq(name))
|
||||
}
|
||||
|
||||
pub fn find_active() -> Select<Entity> {
|
||||
Self::find().filter(Column::IsDeleted.eq(false))
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null, default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::roles_permissions::Entity")]
|
||||
RolesPermissions,
|
||||
}
|
||||
|
||||
impl Related<super::roles_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::RolesPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Entity {
|
||||
pub fn find_by_id(id: Uuid) -> Select<Entity> {
|
||||
Self::find().filter(Column::Id.eq(id))
|
||||
}
|
||||
|
||||
pub fn find_by_name(name: &str) -> Select<Entity> {
|
||||
Self::find().filter(Column::Name.eq(name))
|
||||
}
|
||||
|
||||
pub fn find_active() -> Select<Entity> {
|
||||
Self::find().filter(Column::IsDeleted.eq(false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +1,148 @@
|
||||
//! SeaORM entity for Roles table
|
||||
//! Corresponding to ResourceEnum::Roles
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_roles")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_system_role: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_default: bool,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub permissions: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for Role creation
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct RoleBuilder {
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
is_system_role: Option<bool>,
|
||||
is_default: Option<bool>,
|
||||
permissions: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl RoleBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = Some(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_system_role(mut self, is_system_role: bool) -> Self {
|
||||
self.is_system_role = Some(is_system_role);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_default(mut self, is_default: bool) -> Self {
|
||||
self.is_default = Some(is_default);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn permissions(mut self, permissions: Vec<String>) -> Self {
|
||||
self.permissions = Some(permissions);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(name) = self.name {
|
||||
active_model.name = Set(name);
|
||||
} else {
|
||||
return Err("Role name is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(description) = self.description {
|
||||
active_model.description = Set(description);
|
||||
} else {
|
||||
return Err("Role description is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(is_system_role) = self.is_system_role {
|
||||
active_model.is_system_role = Set(is_system_role);
|
||||
}
|
||||
|
||||
if let Some(is_default) = self.is_default {
|
||||
active_model.is_default = Set(is_default);
|
||||
}
|
||||
|
||||
if let Some(permissions) = self.permissions {
|
||||
active_model.permissions = Set(Some(serde_json::Value::Array(
|
||||
permissions.into_iter().map(serde_json::Value::String).collect()
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_role_model_creation() {
|
||||
let role = RoleBuilder::new()
|
||||
.name("admin".to_string())
|
||||
.description("Administrator role".to_string())
|
||||
.is_system_role(true)
|
||||
.is_default(false)
|
||||
.build();
|
||||
|
||||
assert!(role.is_ok());
|
||||
let role_model = role.unwrap();
|
||||
assert_eq!(role_model.name, Set("admin".to_string()));
|
||||
assert_eq!(role_model.description, Set("Administrator role".to_string()));
|
||||
assert_eq!(role_model.is_system_role, Set(true));
|
||||
assert_eq!(role_model.is_default, Set(false));
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_roles")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_system_role: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_default: bool,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub permissions: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct RoleBuilder {
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
is_system_role: Option<bool>,
|
||||
is_default: Option<bool>,
|
||||
permissions: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl RoleBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = Some(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_system_role(mut self, is_system_role: bool) -> Self {
|
||||
self.is_system_role = Some(is_system_role);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_default(mut self, is_default: bool) -> Self {
|
||||
self.is_default = Some(is_default);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn permissions(mut self, permissions: Vec<String>) -> Self {
|
||||
self.permissions = Some(permissions);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(name) = self.name {
|
||||
active_model.name = Set(name);
|
||||
} else {
|
||||
return Err("Role name is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(description) = self.description {
|
||||
active_model.description = Set(description);
|
||||
} else {
|
||||
return Err("Role description is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(is_system_role) = self.is_system_role {
|
||||
active_model.is_system_role = Set(is_system_role);
|
||||
}
|
||||
|
||||
if let Some(is_default) = self.is_default {
|
||||
active_model.is_default = Set(is_default);
|
||||
}
|
||||
|
||||
if let Some(permissions) = self.permissions {
|
||||
active_model.permissions = Set(Some(serde_json::Value::Array(
|
||||
permissions
|
||||
.into_iter()
|
||||
.map(serde_json::Value::String)
|
||||
.collect(),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_role_model_creation() {
|
||||
let role = RoleBuilder::new()
|
||||
.name("admin".to_string())
|
||||
.description("Administrator role".to_string())
|
||||
.is_system_role(true)
|
||||
.is_default(false)
|
||||
.build();
|
||||
|
||||
assert!(role.is_ok());
|
||||
let role_model = role.unwrap();
|
||||
assert_eq!(role_model.name, Set("admin".to_string()));
|
||||
assert_eq!(
|
||||
role_model.description,
|
||||
Set("Administrator role".to_string())
|
||||
);
|
||||
assert_eq!(role_model.is_system_role, Set(true));
|
||||
assert_eq!(role_model.is_default, Set(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,159 +1,165 @@
|
||||
//! SeaORM entity for RolesPermissions table
|
||||
//! Corresponding to ResourceEnum::RolesPermissions
|
||||
//! Represents the many-to-many relationship between Users and Roles
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_roles_permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub role_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub permission_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub assigned_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "false")]
|
||||
pub is_active: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(belongs_to = "super::users::Entity", from = "Column::UserId", to = "super::users::Column::Id")]
|
||||
User,
|
||||
#[sea_orm(belongs_to = "super::roles::Entity", from = "Column::RoleId", to = "super::roles::Column::Id")]
|
||||
Role,
|
||||
#[sea_orm(belongs_to = "super::permissions::Entity", from = "Column::PermissionId", to = "super::permissions::Column::Id")]
|
||||
Permission,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::roles::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Role.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Permission.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for RolePermission creation
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct RolePermissionBuilder {
|
||||
user_id: Option<Uuid>,
|
||||
role_id: Option<Uuid>,
|
||||
permission_id: Option<Uuid>,
|
||||
is_active: Option<bool>,
|
||||
}
|
||||
|
||||
impl RolePermissionBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn role_id(mut self, role_id: Uuid) -> Self {
|
||||
self.role_id = Some(role_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn permission_id(mut self, permission_id: Uuid) -> Self {
|
||||
self.permission_id = Some(permission_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_active(mut self, is_active: bool) -> Self {
|
||||
self.is_active = Some(is_active);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let (Some(user_id), Some(role_id), Some(permission_id)) = (self.user_id, self.role_id, self.permission_id) {
|
||||
active_model.user_id = Set(user_id);
|
||||
active_model.role_id = Set(role_id);
|
||||
active_model.permission_id = Set(permission_id);
|
||||
} else {
|
||||
return Err("User ID, Role ID, and Permission ID are required".to_string());
|
||||
}
|
||||
|
||||
if let Some(is_active) = self.is_active {
|
||||
active_model.is_active = Set(is_active);
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::seaorm::common::utils::generate_uuid;
|
||||
|
||||
#[test]
|
||||
fn test_role_permission_model_creation() {
|
||||
let user_id = generate_uuid();
|
||||
let role_id = generate_uuid();
|
||||
let permission_id = generate_uuid();
|
||||
|
||||
let role_permission = RolePermissionBuilder::new()
|
||||
.user_id(user_id)
|
||||
.role_id(role_id)
|
||||
.permission_id(permission_id)
|
||||
.is_active(true)
|
||||
.build();
|
||||
|
||||
assert!(role_permission.is_ok());
|
||||
let role_permission_model = role_permission.unwrap();
|
||||
assert_eq!(role_permission_model.user_id, Set(user_id));
|
||||
assert_eq!(role_permission_model.role_id, Set(role_id));
|
||||
assert_eq!(role_permission_model.permission_id, Set(permission_id));
|
||||
assert_eq!(role_permission_model.is_active, Set(true));
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_roles_permissions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub role_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub permission_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub assigned_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "false")]
|
||||
pub is_active: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
User,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::roles::Entity",
|
||||
from = "Column::RoleId",
|
||||
to = "super::roles::Column::Id"
|
||||
)]
|
||||
Role,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::permissions::Entity",
|
||||
from = "Column::PermissionId",
|
||||
to = "super::permissions::Column::Id"
|
||||
)]
|
||||
Permission,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::roles::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Role.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Permission.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct RolePermissionBuilder {
|
||||
user_id: Option<Uuid>,
|
||||
role_id: Option<Uuid>,
|
||||
permission_id: Option<Uuid>,
|
||||
is_active: Option<bool>,
|
||||
}
|
||||
|
||||
impl RolePermissionBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn role_id(mut self, role_id: Uuid) -> Self {
|
||||
self.role_id = Some(role_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn permission_id(mut self, permission_id: Uuid) -> Self {
|
||||
self.permission_id = Some(permission_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_active(mut self, is_active: bool) -> Self {
|
||||
self.is_active = Some(is_active);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let (Some(user_id), Some(role_id), Some(permission_id)) =
|
||||
(self.user_id, self.role_id, self.permission_id)
|
||||
{
|
||||
active_model.user_id = Set(user_id);
|
||||
active_model.role_id = Set(role_id);
|
||||
active_model.permission_id = Set(permission_id);
|
||||
} else {
|
||||
return Err("User ID, Role ID, and Permission ID are required".to_string());
|
||||
}
|
||||
|
||||
if let Some(is_active) = self.is_active {
|
||||
active_model.is_active = Set(is_active);
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::seaorm::common::utils::generate_uuid;
|
||||
|
||||
#[test]
|
||||
fn test_role_permission_model_creation() {
|
||||
let user_id = generate_uuid();
|
||||
let role_id = generate_uuid();
|
||||
let permission_id = generate_uuid();
|
||||
|
||||
let role_permission = RolePermissionBuilder::new()
|
||||
.user_id(user_id)
|
||||
.role_id(role_id)
|
||||
.permission_id(permission_id)
|
||||
.is_active(true)
|
||||
.build();
|
||||
|
||||
assert!(role_permission.is_ok());
|
||||
let role_permission_model = role_permission.unwrap();
|
||||
assert_eq!(role_permission_model.user_id, Set(user_id));
|
||||
assert_eq!(role_permission_model.role_id, Set(role_id));
|
||||
assert_eq!(role_permission_model.permission_id, Set(permission_id));
|
||||
assert_eq!(role_permission_model.is_active, Set(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "sessions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub mentor_id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub mentee_id: Uuid,
|
||||
|
||||
pub topic: String,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub description: Option<String>,
|
||||
|
||||
pub scheduled_at: DateTime<Utc>,
|
||||
|
||||
pub duration_minutes: i32,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub meeting_link: Option<String>,
|
||||
|
||||
pub session_type: String, // "video_call", "phone_call", "chat"
|
||||
|
||||
pub status: String, // "pending", "confirmed", "completed", "cancelled", "no_show"
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub feedback: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub rating: Option<i32>, // 1-5
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub feedback_submitted_at: Option<DateTime<Utc>>,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::MentorId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
Mentor,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::MenteeId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
Mentee,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Mentor.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "sessions")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub mentor_id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub mentee_id: Uuid,
|
||||
|
||||
pub topic: String,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub description: Option<String>,
|
||||
|
||||
pub scheduled_at: DateTime<Utc>,
|
||||
|
||||
pub duration_minutes: i32,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub meeting_link: Option<String>,
|
||||
|
||||
pub session_type: String, // "video_call", "phone_call", "chat"
|
||||
|
||||
pub status: String, // "pending", "confirmed", "completed", "cancelled", "no_show"
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub feedback: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub rating: Option<i32>, // 1-5
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub feedback_submitted_at: Option<DateTime<Utc>>,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::MentorId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
Mentor,
|
||||
|
||||
#[sea_orm(
|
||||
belongs_to = "super::users::Entity",
|
||||
from = "Column::MenteeId",
|
||||
to = "super::users::Column::Id"
|
||||
)]
|
||||
Mentee,
|
||||
}
|
||||
|
||||
impl Related<super::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Mentor.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -1,178 +1,180 @@
|
||||
//! SeaORM entity for Users table
|
||||
//! Corresponding to ResourceEnum::Users
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, imphnen_macros::Builder)]
|
||||
#[sea_orm(table_name = "app_users")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub email: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub password_hash: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub username: String,
|
||||
|
||||
#[sea_orm(column_name = "role_id", nullable)]
|
||||
pub role_id: Option<Uuid>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub first_name: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub last_name: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub avatar_url: Option<String>,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_verified: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_active: bool,
|
||||
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::roles_permissions::Entity")]
|
||||
RolesPermissions,
|
||||
#[sea_orm(belongs_to = "super::roles::Entity", from = "Column::RoleId", to = "super::roles::Column::Id")]
|
||||
Role,
|
||||
}
|
||||
|
||||
impl Related<super::roles_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::RolesPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::roles::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Role.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for User creation
|
||||
// Generated by #[derive(Builder)]
|
||||
pub type UserBuilder = ModelBuilder;
|
||||
|
||||
impl ModelBuilder {
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(email) = self.email {
|
||||
active_model.email = Set(email);
|
||||
} else {
|
||||
return Err("Email is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(password_hash) = self.password_hash {
|
||||
active_model.password_hash = Set(password_hash);
|
||||
} else {
|
||||
return Err("Password hash is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(username) = self.username {
|
||||
active_model.username = Set(username);
|
||||
} else {
|
||||
return Err("Username is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(role_id) = self.role_id {
|
||||
active_model.role_id = Set(Some(role_id));
|
||||
}
|
||||
|
||||
if let Some(first_name) = self.first_name {
|
||||
active_model.first_name = Set(Some(first_name));
|
||||
}
|
||||
|
||||
if let Some(last_name) = self.last_name {
|
||||
active_model.last_name = Set(Some(last_name));
|
||||
}
|
||||
|
||||
if let Some(avatar_url) = self.avatar_url {
|
||||
active_model.avatar_url = Set(Some(avatar_url));
|
||||
}
|
||||
|
||||
if let Some(is_verified) = self.is_verified {
|
||||
active_model.is_verified = Set(is_verified);
|
||||
}
|
||||
|
||||
if let Some(is_active) = self.is_active {
|
||||
active_model.is_active = Set(is_active);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_user_model_creation() {
|
||||
let user = UserBuilder::new()
|
||||
.email("test@example.com".to_string())
|
||||
.password_hash("hashed_password".to_string())
|
||||
.username("testuser".to_string())
|
||||
.first_name("Test".to_string())
|
||||
.last_name("User".to_string())
|
||||
.is_verified(true)
|
||||
.is_active(true)
|
||||
.build();
|
||||
|
||||
assert!(user.is_ok());
|
||||
let user_model = user.unwrap();
|
||||
assert_eq!(user_model.email, Set("test@example.com".to_string()));
|
||||
assert_eq!(user_model.password_hash, Set("hashed_password".to_string()));
|
||||
assert_eq!(user_model.username, Set("testuser".to_string()));
|
||||
assert_eq!(user_model.first_name, Set(Some("Test".to_string())));
|
||||
assert_eq!(user_model.last_name, Set(Some("User".to_string())));
|
||||
assert_eq!(user_model.is_verified, Set(true));
|
||||
assert_eq!(user_model.is_active, Set(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_model_missing_required_fields() {
|
||||
let user = UserBuilder::new()
|
||||
.email("test@example.com".to_string())
|
||||
// Missing password_hash
|
||||
.username("testuser".to_string())
|
||||
.build();
|
||||
|
||||
assert!(user.is_err());
|
||||
assert_eq!(user.unwrap_err(), "Password hash is required");
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
DeriveEntityModel,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
imphnen_macros::Builder,
|
||||
)]
|
||||
#[sea_orm(table_name = "app_users")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub email: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub password_hash: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub username: String,
|
||||
|
||||
#[sea_orm(column_name = "role_id", nullable)]
|
||||
pub role_id: Option<Uuid>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub first_name: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub last_name: Option<String>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub avatar_url: Option<String>,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_verified: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_active: bool,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::roles_permissions::Entity")]
|
||||
RolesPermissions,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::roles::Entity",
|
||||
from = "Column::RoleId",
|
||||
to = "super::roles::Column::Id"
|
||||
)]
|
||||
Role,
|
||||
}
|
||||
|
||||
impl Related<super::roles_permissions::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::RolesPermissions.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::roles::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Role.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
pub type UserBuilder = ModelBuilder;
|
||||
|
||||
impl ModelBuilder {
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(email) = self.email {
|
||||
active_model.email = Set(email);
|
||||
} else {
|
||||
return Err("Email is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(password_hash) = self.password_hash {
|
||||
active_model.password_hash = Set(password_hash);
|
||||
} else {
|
||||
return Err("Password hash is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(username) = self.username {
|
||||
active_model.username = Set(username);
|
||||
} else {
|
||||
return Err("Username is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(role_id) = self.role_id {
|
||||
active_model.role_id = Set(Some(role_id));
|
||||
}
|
||||
|
||||
if let Some(first_name) = self.first_name {
|
||||
active_model.first_name = Set(Some(first_name));
|
||||
}
|
||||
|
||||
if let Some(last_name) = self.last_name {
|
||||
active_model.last_name = Set(Some(last_name));
|
||||
}
|
||||
|
||||
if let Some(avatar_url) = self.avatar_url {
|
||||
active_model.avatar_url = Set(Some(avatar_url));
|
||||
}
|
||||
|
||||
if let Some(is_verified) = self.is_verified {
|
||||
active_model.is_verified = Set(is_verified);
|
||||
}
|
||||
|
||||
if let Some(is_active) = self.is_active {
|
||||
active_model.is_active = Set(is_active);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_user_model_creation() {
|
||||
let user = UserBuilder::new()
|
||||
.email("test@example.com".to_string())
|
||||
.password_hash("hashed_password".to_string())
|
||||
.username("testuser".to_string())
|
||||
.first_name("Test".to_string())
|
||||
.last_name("User".to_string())
|
||||
.is_verified(true)
|
||||
.is_active(true)
|
||||
.build();
|
||||
|
||||
assert!(user.is_ok());
|
||||
let user_model = user.unwrap();
|
||||
assert_eq!(user_model.email, Set("test@example.com".to_string()));
|
||||
assert_eq!(user_model.password_hash, Set("hashed_password".to_string()));
|
||||
assert_eq!(user_model.username, Set("testuser".to_string()));
|
||||
assert_eq!(user_model.first_name, Set(Some("Test".to_string())));
|
||||
assert_eq!(user_model.last_name, Set(Some("User".to_string())));
|
||||
assert_eq!(user_model.is_verified, Set(true));
|
||||
assert_eq!(user_model.is_active, Set(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user_model_missing_required_fields() {
|
||||
let user = UserBuilder::new()
|
||||
.email("test@example.com".to_string())
|
||||
.username("testuser".to_string())
|
||||
.build();
|
||||
|
||||
assert!(user.is_err());
|
||||
assert_eq!(user.unwrap_err(), "Password hash is required");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
//! SeaORM Entity for AuditLog
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "app_audit_log")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub user_email: String,
|
||||
pub action: String,
|
||||
pub resource: String,
|
||||
pub resource_id: Option<String>,
|
||||
#[sea_orm(column_type = "JsonBinary", nullable)]
|
||||
pub old_data: Option<Json>,
|
||||
#[sea_orm(column_type = "JsonBinary", nullable)]
|
||||
pub new_data: Option<Json>,
|
||||
pub ip_address: String,
|
||||
pub user_agent: Option<String>,
|
||||
pub timestamp: DateTimeWithTimeZone,
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub user_email: String,
|
||||
pub action: String,
|
||||
pub resource: String,
|
||||
pub resource_id: Option<String>,
|
||||
#[sea_orm(column_type = "JsonBinary", nullable)]
|
||||
pub old_data: Option<Json>,
|
||||
#[sea_orm(column_type = "JsonBinary", nullable)]
|
||||
pub new_data: Option<Json>,
|
||||
pub ip_address: String,
|
||||
pub user_agent: Option<String>,
|
||||
pub timestamp: DateTimeWithTimeZone,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
use super::enums::ResourceEnum;
|
||||
use std::fmt;
|
||||
|
||||
impl fmt::Display for ResourceEnum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
@@ -1,206 +1,101 @@
|
||||
//! Enum definitions for SeaORM entities
|
||||
//! Provides resource type enumerations matching SurrealDB ResourceEnum
|
||||
|
||||
use std::fmt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::types::PgUuid;
|
||||
|
||||
/// Database resource enumeration for SeaORM
|
||||
/// Matches the SurrealDB ResourceEnum with PostgreSQL compatibility
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ResourceEnum {
|
||||
/// OTP cache table for temporary authentication codes
|
||||
OtpCache,
|
||||
/// User cache table for user session data
|
||||
UsersCache,
|
||||
/// Gacha items table
|
||||
GachaItems,
|
||||
/// Gacha claims table for user item claims
|
||||
GachaClaims,
|
||||
/// Gacha rolls table for user roll history
|
||||
GachaRolls,
|
||||
/// Gacha credits table for user currency
|
||||
GachaCredits,
|
||||
/// Users table for user accounts
|
||||
Users,
|
||||
/// Roles table for user roles
|
||||
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,
|
||||
/// Notifications table for user notifications
|
||||
Notifications,
|
||||
/// Rate limiting table for IP-based rate limiting
|
||||
RateLimit,
|
||||
/// Audit log table for admin action tracking
|
||||
AuditLog,
|
||||
/// Sessions table for mentoring sessions
|
||||
Sessions,
|
||||
/// Migration status tracking table
|
||||
MigrationStatus,
|
||||
}
|
||||
|
||||
impl fmt::Display for ResourceEnum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let table_name = 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::Notifications => "app_notifications",
|
||||
ResourceEnum::RateLimit => "app_rate_limit",
|
||||
ResourceEnum::AuditLog => "app_audit_log",
|
||||
ResourceEnum::Sessions => "app_sessions",
|
||||
ResourceEnum::MigrationStatus => "app_migration_status",
|
||||
};
|
||||
write!(f, "{}", table_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceEnum {
|
||||
/// Get the table name as a string slice.
|
||||
///
|
||||
/// # Returns
|
||||
/// The PostgreSQL table name for this resource
|
||||
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::Notifications => "app_notifications",
|
||||
ResourceEnum::RateLimit => "app_rate_limit",
|
||||
ResourceEnum::AuditLog => "app_audit_log",
|
||||
ResourceEnum::Sessions => "app_sessions",
|
||||
ResourceEnum::MigrationStatus => "app_migration_status",
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the schema name for the resource
|
||||
///
|
||||
/// # Returns
|
||||
/// The database schema name (usually "public" for PostgreSQL)
|
||||
pub fn schema(&self) -> &'static str {
|
||||
"public"
|
||||
}
|
||||
|
||||
/// Create a SeaORM entity name from the resource enum
|
||||
///
|
||||
/// # Returns
|
||||
/// A string suitable for use as a SeaORM entity name
|
||||
pub fn to_entity_name(&self) -> String {
|
||||
self.as_str().replace("app_", "").to_pascal_case()
|
||||
}
|
||||
|
||||
/// 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
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a reference ID for the resource
|
||||
///
|
||||
/// # Returns
|
||||
/// A formatted string suitable for use as a reference ID
|
||||
pub fn generate_ref_id(&self, uuid: &PgUuid) -> String {
|
||||
format!("{}_{}", self.as_str().replace("app_", ""), uuid.0)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper trait for string case conversion
|
||||
trait ToPascalCase {
|
||||
fn to_pascal_case(&self) -> String;
|
||||
}
|
||||
|
||||
impl ToPascalCase for str {
|
||||
fn to_pascal_case(&self) -> String {
|
||||
self.split('_')
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_resource_enum_table_names() {
|
||||
assert_eq!(ResourceEnum::Users.as_str(), "app_users");
|
||||
assert_eq!(ResourceEnum::Roles.as_str(), "app_roles");
|
||||
assert_eq!(ResourceEnum::GachaItems.as_str(), "app_gacha_items");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resource_enum_display() {
|
||||
assert_eq!(format!("{}", ResourceEnum::Users), "app_users");
|
||||
assert_eq!(format!("{}", ResourceEnum::RolesPermissions), "app_roles_permissions");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resource_enum_categories() {
|
||||
assert!(ResourceEnum::Users.is_user_related());
|
||||
assert!(ResourceEnum::GachaItems.is_gacha());
|
||||
assert!(ResourceEnum::OtpCache.is_cache());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resource_enum_to_entity_name() {
|
||||
assert_eq!(ResourceEnum::Users.to_entity_name(), "Users");
|
||||
assert_eq!(ResourceEnum::RolesPermissions.to_entity_name(), "RolesPermissions");
|
||||
assert_eq!(ResourceEnum::GachaItems.to_entity_name(), "GachaItems");
|
||||
}
|
||||
}
|
||||
use super::types::PgUuid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ResourceEnum {
|
||||
OtpCache,
|
||||
UsersCache,
|
||||
GachaItems,
|
||||
GachaClaims,
|
||||
GachaRolls,
|
||||
GachaCredits,
|
||||
Users,
|
||||
Roles,
|
||||
Permissions,
|
||||
RolesPermissions,
|
||||
Events,
|
||||
Testimonials,
|
||||
Mentors,
|
||||
Notifications,
|
||||
RateLimit,
|
||||
AuditLog,
|
||||
Sessions,
|
||||
MigrationStatus,
|
||||
}
|
||||
|
||||
impl ResourceEnum {
|
||||
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::Notifications => "app_notifications",
|
||||
ResourceEnum::RateLimit => "app_rate_limit",
|
||||
ResourceEnum::AuditLog => "app_audit_log",
|
||||
ResourceEnum::Sessions => "app_sessions",
|
||||
ResourceEnum::MigrationStatus => "app_migration_status",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn schema(&self) -> &'static str {
|
||||
"public"
|
||||
}
|
||||
|
||||
pub fn to_entity_name(&self) -> String {
|
||||
self.as_str().replace("app_", "").to_pascal_case()
|
||||
}
|
||||
|
||||
pub fn is_cache(&self) -> bool {
|
||||
matches!(self, ResourceEnum::OtpCache | ResourceEnum::UsersCache)
|
||||
}
|
||||
|
||||
pub fn is_gacha(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
ResourceEnum::GachaItems
|
||||
| ResourceEnum::GachaClaims
|
||||
| ResourceEnum::GachaRolls
|
||||
| ResourceEnum::GachaCredits
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_user_related(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
ResourceEnum::Users | ResourceEnum::UsersCache | ResourceEnum::Mentors
|
||||
)
|
||||
}
|
||||
|
||||
pub fn generate_ref_id(&self, uuid: &PgUuid) -> String {
|
||||
format!("{}_{}", self.as_str().replace("app_", ""), uuid.0)
|
||||
}
|
||||
}
|
||||
|
||||
trait ToPascalCase {
|
||||
fn to_pascal_case(&self) -> String;
|
||||
}
|
||||
|
||||
impl ToPascalCase for str {
|
||||
fn to_pascal_case(&self) -> String {
|
||||
self
|
||||
.split('_')
|
||||
.map(|s| {
|
||||
let mut chars = s.chars();
|
||||
chars
|
||||
.next()
|
||||
.map(|c| c.to_uppercase().collect::<String>() + chars.as_str())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,49 @@
|
||||
//! SeaORM entity for Events table
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "events")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub detail_link: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub price: f64,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_online: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub location: Option<String>,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub start_date: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub end_date: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "events")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub detail_link: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub price: f64,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_online: bool,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub location: Option<String>,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub start_date: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub end_date: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
pub mod audit_log;
|
||||
pub mod enum_impls;
|
||||
pub mod enums;
|
||||
pub mod events;
|
||||
pub mod rate_limit;
|
||||
pub mod testimonials;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
pub mod audit_log;
|
||||
pub mod rate_limit;
|
||||
pub mod events;
|
||||
pub mod testimonials;
|
||||
|
||||
pub use enums::ResourceEnum;
|
||||
pub use types::PgUuid;
|
||||
pub use utils::{generate_uuid, current_timestamp};
|
||||
pub use utils::{current_timestamp, generate_uuid};
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
//! SeaORM Entity for RateLimit
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "app_rate_limit")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: String,
|
||||
pub ip_address: String,
|
||||
pub request_count: u32,
|
||||
pub first_request_time: DateTimeWithTimeZone,
|
||||
pub last_request_time: DateTimeWithTimeZone,
|
||||
pub window_duration_secs: i64,
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: String,
|
||||
pub ip_address: String,
|
||||
pub request_count: u32,
|
||||
pub first_request_time: DateTimeWithTimeZone,
|
||||
pub last_request_time: DateTimeWithTimeZone,
|
||||
pub window_duration_secs: i64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
||||
@@ -1,51 +1,49 @@
|
||||
//! SeaORM entity for Testimonials table
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid; // Added Uuid import
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "testimonials")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null, column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub role: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub content: String,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "crate::seaorm::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "crate::seaorm::auth::users::Column::Id",
|
||||
on_update = "NoAction",
|
||||
on_delete = "NoAction"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<crate::seaorm::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "testimonials")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null, column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub role: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub content: String,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_deleted: bool,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "crate::seaorm::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "crate::seaorm::auth::users::Column::Id",
|
||||
on_update = "NoAction",
|
||||
on_delete = "NoAction"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<crate::seaorm::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -1,73 +1,63 @@
|
||||
//! Shared type definitions for SeaORM entities
|
||||
//! Provides PostgreSQL-compatible type aliases and custom types
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
/// UUID type alias for PostgreSQL UUID compatibility
|
||||
/// Uses `Uuid` from the `uuid` crate with SeaORM conversion traits
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct PgUuid(pub Uuid);
|
||||
|
||||
impl From<Uuid> for PgUuid {
|
||||
fn from(uuid: Uuid) -> Self {
|
||||
Self(uuid)
|
||||
}
|
||||
fn from(uuid: Uuid) -> Self {
|
||||
Self(uuid)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PgUuid> for Uuid {
|
||||
fn from(pg_uuid: PgUuid) -> Self {
|
||||
pg_uuid.0
|
||||
}
|
||||
fn from(pg_uuid: PgUuid) -> Self {
|
||||
pg_uuid.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PgUuid> for String {
|
||||
fn from(pg_uuid: PgUuid) -> Self {
|
||||
pg_uuid.0.to_string()
|
||||
}
|
||||
fn from(pg_uuid: PgUuid) -> Self {
|
||||
pg_uuid.0.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Timestamp type alias for PostgreSQL TIMESTAMP with time zone
|
||||
/// Uses `DateTime<Utc>` from the `chrono` crate
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PgTimestamp(pub DateTime<Utc>);
|
||||
|
||||
impl From<DateTime<Utc>> for PgTimestamp {
|
||||
fn from(timestamp: DateTime<Utc>) -> Self {
|
||||
Self(timestamp)
|
||||
}
|
||||
fn from(timestamp: DateTime<Utc>) -> Self {
|
||||
Self(timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PgTimestamp> for DateTime<Utc> {
|
||||
fn from(pg_timestamp: PgTimestamp) -> Self {
|
||||
pg_timestamp.0
|
||||
}
|
||||
fn from(pg_timestamp: PgTimestamp) -> Self {
|
||||
pg_timestamp.0
|
||||
}
|
||||
}
|
||||
|
||||
/// JSONB type alias for PostgreSQL JSONB compatibility
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PgJsonB<T>(pub T);
|
||||
|
||||
impl<T> From<T> for PgJsonB<T>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
T: serde::Serialize,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
fn from(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Common fields that should be included in all entities
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CommonFields {
|
||||
pub id: PgUuid,
|
||||
pub created_at: PgTimestamp,
|
||||
pub updated_at: PgTimestamp,
|
||||
pub deleted_at: Option<PgTimestamp>,
|
||||
pub id: PgUuid,
|
||||
pub created_at: PgTimestamp,
|
||||
pub updated_at: PgTimestamp,
|
||||
pub deleted_at: Option<PgTimestamp>,
|
||||
}
|
||||
|
||||
// Helper macros for common field definitions
|
||||
#[macro_export]
|
||||
macro_rules! common_fields {
|
||||
() => {
|
||||
@@ -86,4 +76,3 @@ macro_rules! common_fields {
|
||||
.default(None),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,90 +1,74 @@
|
||||
//! Utility functions for SeaORM entities
|
||||
//! Provides helper functions for UUID generation, timestamp handling, and resource management
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::types::{PgTimestamp, PgUuid};
|
||||
|
||||
/// Generate a new UUID for entity IDs
|
||||
/// Uses cryptographically secure random UUID version 4
|
||||
pub fn generate_uuid() -> Uuid {
|
||||
Uuid::new_v4()
|
||||
}
|
||||
|
||||
/// Generate a new timestamp for entity timestamps
|
||||
/// Uses UTC timezone with millisecond precision
|
||||
pub fn generate_timestamp() -> PgTimestamp {
|
||||
PgTimestamp(DateTime::from_timestamp_millis(Utc::now().timestamp_millis()).unwrap())
|
||||
}
|
||||
|
||||
/// Convert a string to PgUuid
|
||||
/// Returns Result<PgUuid, String> with error message on failure
|
||||
pub fn string_to_uuid(uuid_str: &str) -> Result<PgUuid, String> {
|
||||
Uuid::parse_str(uuid_str)
|
||||
.map(PgUuid)
|
||||
.map_err(|e| format!("Invalid UUID format: {e}"))
|
||||
}
|
||||
|
||||
/// Convert PgUuid to string representation
|
||||
pub fn uuid_to_string(uuid: &uuid::Uuid) -> String {
|
||||
uuid.to_string()
|
||||
}
|
||||
|
||||
/// Get current timestamp as DateTime<Utc>
|
||||
pub fn current_timestamp() -> DateTime<Utc> {
|
||||
Utc::now()
|
||||
}
|
||||
|
||||
/// Format timestamp for display
|
||||
pub fn format_timestamp(timestamp: &PgTimestamp) -> String {
|
||||
timestamp.0.format("%Y-%m-%d %H:%M:%S UTC").to_string()
|
||||
}
|
||||
|
||||
/// Create a soft delete timestamp
|
||||
pub fn create_deleted_at() -> Option<DateTime<Utc>> {
|
||||
Some(current_timestamp())
|
||||
}
|
||||
|
||||
/// Remove soft delete timestamp
|
||||
pub fn remove_deleted_at() -> Option<PgTimestamp> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generate_uuid() {
|
||||
let uuid1 = generate_uuid();
|
||||
let uuid2 = generate_uuid();
|
||||
assert_ne!(uuid1, uuid2);
|
||||
assert!(Uuid::parse_str(&uuid_to_string(&uuid1)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_timestamp() {
|
||||
let ts1 = generate_timestamp();
|
||||
let ts2 = generate_timestamp();
|
||||
// Timestamps should be close to each other
|
||||
let diff = ts2.0.signed_duration_since(ts1.0).num_milliseconds();
|
||||
assert!(diff >= 0);
|
||||
assert!(diff < 1000); // Should be within 1 second
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_to_uuid() {
|
||||
let uuid_str = "123e4567-e89b-12d3-a456-426614174000";
|
||||
let result = string_to_uuid(uuid_str);
|
||||
assert!(result.is_ok());
|
||||
let uuid = result.unwrap();
|
||||
// `uuid` is a `PgUuid`; convert to `Uuid` before comparing string representation
|
||||
let uuid_plain: uuid::Uuid = uuid.into();
|
||||
assert_eq!(uuid_to_string(&uuid_plain), uuid_str);
|
||||
|
||||
let invalid_uuid = "invalid-uuid";
|
||||
let result = string_to_uuid(invalid_uuid);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::types::{PgTimestamp, PgUuid};
|
||||
|
||||
pub fn generate_uuid() -> Uuid {
|
||||
Uuid::new_v4()
|
||||
}
|
||||
|
||||
pub fn generate_timestamp() -> PgTimestamp {
|
||||
PgTimestamp(Utc::now())
|
||||
}
|
||||
|
||||
pub fn string_to_uuid(uuid_str: &str) -> Result<PgUuid, String> {
|
||||
Uuid::parse_str(uuid_str)
|
||||
.map(PgUuid)
|
||||
.map_err(|e| format!("Invalid UUID format: {e}"))
|
||||
}
|
||||
|
||||
pub fn uuid_to_string(uuid: &uuid::Uuid) -> String {
|
||||
uuid.to_string()
|
||||
}
|
||||
|
||||
pub fn current_timestamp() -> DateTime<Utc> {
|
||||
Utc::now()
|
||||
}
|
||||
|
||||
pub fn format_timestamp(timestamp: &PgTimestamp) -> String {
|
||||
timestamp.0.format("%Y-%m-%d %H:%M:%S UTC").to_string()
|
||||
}
|
||||
|
||||
pub fn create_deleted_at() -> Option<DateTime<Utc>> {
|
||||
Some(current_timestamp())
|
||||
}
|
||||
|
||||
pub fn remove_deleted_at() -> Option<PgTimestamp> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generate_uuid() {
|
||||
let uuid1 = generate_uuid();
|
||||
let uuid2 = generate_uuid();
|
||||
assert_ne!(uuid1, uuid2);
|
||||
assert!(Uuid::parse_str(&uuid_to_string(&uuid1)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_timestamp() {
|
||||
let ts1 = generate_timestamp();
|
||||
let ts2 = generate_timestamp();
|
||||
let diff = ts2.0.signed_duration_since(ts1.0).num_milliseconds();
|
||||
assert!(diff >= 0);
|
||||
assert!(diff < 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_to_uuid() {
|
||||
let uuid_str = "123e4567-e89b-12d3-a456-426614174000";
|
||||
let result = string_to_uuid(uuid_str);
|
||||
assert!(result.is_ok());
|
||||
let uuid = result.unwrap();
|
||||
let uuid_plain: uuid::Uuid = uuid.into();
|
||||
assert_eq!(uuid_to_string(&uuid_plain), uuid_str);
|
||||
|
||||
let invalid_uuid = "invalid-uuid";
|
||||
let result = string_to_uuid(invalid_uuid);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,178 +1,170 @@
|
||||
//! SeaORM entity for GachaClaims table
|
||||
//! Corresponding to ResourceEnum::GachaClaims
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_gacha_claims")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub gacha_item_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub claim_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub claim_type: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub status: String,
|
||||
|
||||
#[sea_orm(default = "0")]
|
||||
pub quantity: i32,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub claimed_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for GachaClaim creation
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct GachaClaimBuilder {
|
||||
user_id: Option<Uuid>,
|
||||
gacha_item_id: Option<Uuid>,
|
||||
claim_type: Option<String>,
|
||||
status: Option<String>,
|
||||
quantity: Option<i32>,
|
||||
metadata: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl GachaClaimBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gacha_item_id(mut self, gacha_item_id: Uuid) -> Self {
|
||||
self.gacha_item_id = Some(gacha_item_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn claim_type(mut self, claim_type: String) -> Self {
|
||||
self.claim_type = Some(claim_type);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn status(mut self, status: String) -> Self {
|
||||
self.status = Some(status);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn quantity(mut self, quantity: i32) -> Self {
|
||||
self.quantity = Some(quantity);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
|
||||
self.metadata = Some(metadata);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(user_id) = self.user_id {
|
||||
active_model.user_id = Set(user_id);
|
||||
} else {
|
||||
return Err("User ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(gacha_item_id) = self.gacha_item_id {
|
||||
active_model.gacha_item_id = Set(gacha_item_id);
|
||||
} else {
|
||||
return Err("Gacha Item ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(claim_type) = self.claim_type {
|
||||
active_model.claim_type = Set(claim_type);
|
||||
} else {
|
||||
return Err("Claim type is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(status) = self.status {
|
||||
active_model.status = Set(status);
|
||||
} else {
|
||||
return Err("Status is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(quantity) = self.quantity {
|
||||
active_model.quantity = Set(quantity);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::seaorm::common::utils::generate_uuid;
|
||||
|
||||
#[test]
|
||||
fn test_gacha_claim_model_creation() {
|
||||
let user_id = generate_uuid();
|
||||
let gacha_item_id = generate_uuid();
|
||||
|
||||
let claim = GachaClaimBuilder::new()
|
||||
.user_id(user_id)
|
||||
.gacha_item_id(gacha_item_id)
|
||||
.claim_type("direct".to_string())
|
||||
.status("claimed".to_string())
|
||||
.quantity(1)
|
||||
.build();
|
||||
|
||||
assert!(claim.is_ok());
|
||||
let claim_model = claim.unwrap();
|
||||
assert_eq!(claim_model.user_id, Set(user_id));
|
||||
assert_eq!(claim_model.gacha_item_id, Set(gacha_item_id));
|
||||
assert_eq!(claim_model.claim_type, Set("direct".to_string()));
|
||||
assert_eq!(claim_model.status, Set("claimed".to_string()));
|
||||
assert_eq!(claim_model.quantity, Set(1));
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_gacha_claims")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub user_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub gacha_item_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub claim_id: Uuid,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub claim_type: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub status: String,
|
||||
|
||||
#[sea_orm(default = "0")]
|
||||
pub quantity: i32,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub claimed_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct GachaClaimBuilder {
|
||||
user_id: Option<Uuid>,
|
||||
gacha_item_id: Option<Uuid>,
|
||||
claim_type: Option<String>,
|
||||
status: Option<String>,
|
||||
quantity: Option<i32>,
|
||||
metadata: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl GachaClaimBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn user_id(mut self, user_id: Uuid) -> Self {
|
||||
self.user_id = Some(user_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn gacha_item_id(mut self, gacha_item_id: Uuid) -> Self {
|
||||
self.gacha_item_id = Some(gacha_item_id);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn claim_type(mut self, claim_type: String) -> Self {
|
||||
self.claim_type = Some(claim_type);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn status(mut self, status: String) -> Self {
|
||||
self.status = Some(status);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn quantity(mut self, quantity: i32) -> Self {
|
||||
self.quantity = Some(quantity);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
|
||||
self.metadata = Some(metadata);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(user_id) = self.user_id {
|
||||
active_model.user_id = Set(user_id);
|
||||
} else {
|
||||
return Err("User ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(gacha_item_id) = self.gacha_item_id {
|
||||
active_model.gacha_item_id = Set(gacha_item_id);
|
||||
} else {
|
||||
return Err("Gacha Item ID is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(claim_type) = self.claim_type {
|
||||
active_model.claim_type = Set(claim_type);
|
||||
} else {
|
||||
return Err("Claim type is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(status) = self.status {
|
||||
active_model.status = Set(status);
|
||||
} else {
|
||||
return Err("Status is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(quantity) = self.quantity {
|
||||
active_model.quantity = Set(quantity);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::seaorm::common::utils::generate_uuid;
|
||||
|
||||
#[test]
|
||||
fn test_gacha_claim_model_creation() {
|
||||
let user_id = generate_uuid();
|
||||
let gacha_item_id = generate_uuid();
|
||||
|
||||
let claim = GachaClaimBuilder::new()
|
||||
.user_id(user_id)
|
||||
.gacha_item_id(gacha_item_id)
|
||||
.claim_type("direct".to_string())
|
||||
.status("claimed".to_string())
|
||||
.quantity(1)
|
||||
.build();
|
||||
|
||||
assert!(claim.is_ok());
|
||||
let claim_model = claim.unwrap();
|
||||
assert_eq!(claim_model.user_id, Set(user_id));
|
||||
assert_eq!(claim_model.gacha_item_id, Set(gacha_item_id));
|
||||
assert_eq!(claim_model.claim_type, Set("direct".to_string()));
|
||||
assert_eq!(claim_model.status, Set("claimed".to_string()));
|
||||
assert_eq!(claim_model.quantity, Set(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid; // Added Uuid import
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "gacha_credits")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
pub available_rolls: i32,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<DateTime>,
|
||||
pub updated_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::auth::users::Column::Id"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::super::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid; // Added Uuid import
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "gacha_credits")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
pub available_rolls: i32,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<DateTime>,
|
||||
pub updated_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::auth::users::Column::Id"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::super::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -1,256 +1,147 @@
|
||||
//! SeaORM entity for GachaItems table
|
||||
//! Corresponding to ResourceEnum::GachaItems
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_gacha_items")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub item_code: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub rarity: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub type_: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub category: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub value: i32,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub weight: f64,
|
||||
|
||||
#[sea_orm(default = "0")]
|
||||
pub stock: i32,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_limited: bool,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
// Builder pattern for GachaItem creation
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct GachaItemBuilder {
|
||||
item_code: Option<String>,
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
rarity: Option<String>,
|
||||
type_: Option<String>,
|
||||
category: Option<String>,
|
||||
value: Option<i32>,
|
||||
weight: Option<f64>,
|
||||
stock: Option<i32>,
|
||||
is_limited: Option<bool>,
|
||||
metadata: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl GachaItemBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn item_code(mut self, item_code: String) -> Self {
|
||||
self.item_code = Some(item_code);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = Some(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rarity(mut self, rarity: String) -> Self {
|
||||
self.rarity = Some(rarity);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn type_(mut self, type_: String) -> Self {
|
||||
self.type_ = Some(type_);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn category(mut self, category: String) -> Self {
|
||||
self.category = Some(category);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn value(mut self, value: i32) -> Self {
|
||||
self.value = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn weight(mut self, weight: f64) -> Self {
|
||||
self.weight = Some(weight);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn stock(mut self, stock: i32) -> Self {
|
||||
self.stock = Some(stock);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_limited(mut self, is_limited: bool) -> Self {
|
||||
self.is_limited = Some(is_limited);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
|
||||
self.metadata = Some(metadata);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(item_code) = self.item_code {
|
||||
active_model.item_code = Set(item_code);
|
||||
} else {
|
||||
return Err("Item code is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(name) = self.name {
|
||||
active_model.name = Set(name);
|
||||
} else {
|
||||
return Err("Name is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(description) = self.description {
|
||||
active_model.description = Set(description);
|
||||
} else {
|
||||
return Err("Description is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(rarity) = self.rarity {
|
||||
active_model.rarity = Set(rarity);
|
||||
} else {
|
||||
return Err("Rarity is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(type_) = self.type_ {
|
||||
active_model.type_ = Set(type_);
|
||||
} else {
|
||||
return Err("Type is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(category) = self.category {
|
||||
active_model.category = Set(category);
|
||||
} else {
|
||||
return Err("Category is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(value) = self.value {
|
||||
active_model.value = Set(value);
|
||||
} else {
|
||||
return Err("Value is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(weight) = self.weight {
|
||||
active_model.weight = Set(weight);
|
||||
} else {
|
||||
return Err("Weight is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(stock) = self.stock {
|
||||
active_model.stock = Set(stock);
|
||||
}
|
||||
|
||||
if let Some(is_limited) = self.is_limited {
|
||||
active_model.is_limited = Set(is_limited);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gacha_item_model_creation() {
|
||||
let item = GachaItemBuilder::new()
|
||||
.item_code("SWORD_001".to_string())
|
||||
.name("Legendary Sword".to_string())
|
||||
.description("A powerful legendary sword".to_string())
|
||||
.rarity("legendary".to_string())
|
||||
.type_("weapon".to_string())
|
||||
.category("sword".to_string())
|
||||
.value(100)
|
||||
.weight(0.01)
|
||||
.stock(10)
|
||||
.is_limited(true)
|
||||
.build();
|
||||
|
||||
assert!(item.is_ok());
|
||||
let item_model = item.unwrap();
|
||||
assert_eq!(item_model.item_code, Set("SWORD_001".to_string()));
|
||||
assert_eq!(item_model.name, Set("Legendary Sword".to_string()));
|
||||
assert_eq!(item_model.description, Set("A powerful legendary sword".to_string()));
|
||||
assert_eq!(item_model.rarity, Set("legendary".to_string()));
|
||||
assert_eq!(item_model.type_, Set("weapon".to_string()));
|
||||
assert_eq!(item_model.category, Set("sword".to_string()));
|
||||
assert_eq!(item_model.value, Set(100));
|
||||
assert_eq!(item_model.weight, Set(0.01));
|
||||
assert_eq!(item_model.stock, Set(10));
|
||||
assert_eq!(item_model.is_limited, Set(true));
|
||||
}
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use sea_orm::{ActiveModelBehavior, DeriveEntityModel, DeriveRelation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "app_gacha_items")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(unique, not_null)]
|
||||
pub item_code: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub name: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub description: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub rarity: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub type_: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub category: String,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub value: i32,
|
||||
|
||||
#[sea_orm(not_null)]
|
||||
pub weight: f64,
|
||||
|
||||
#[sea_orm(default = "0")]
|
||||
pub stock: i32,
|
||||
|
||||
#[sea_orm(default = "false")]
|
||||
pub is_limited: bool,
|
||||
|
||||
#[sea_orm(type = "jsonb", nullable)]
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(not_null, default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(nullable)]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct GachaItemBuilder {
|
||||
pub item_code: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub rarity: Option<String>,
|
||||
pub type_: Option<String>,
|
||||
pub category: Option<String>,
|
||||
pub value: Option<i32>,
|
||||
pub weight: Option<f64>,
|
||||
pub stock: Option<i32>,
|
||||
pub is_limited: Option<bool>,
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
impl GachaItemBuilder {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn item_code(mut self, item_code: String) -> Self {
|
||||
self.item_code = Some(item_code);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn description(mut self, description: String) -> Self {
|
||||
self.description = Some(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rarity(mut self, rarity: String) -> Self {
|
||||
self.rarity = Some(rarity);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn type_(mut self, type_: String) -> Self {
|
||||
self.type_ = Some(type_);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn category(mut self, category: String) -> Self {
|
||||
self.category = Some(category);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn value(mut self, value: i32) -> Self {
|
||||
self.value = Some(value);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn weight(mut self, weight: f64) -> Self {
|
||||
self.weight = Some(weight);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn stock(mut self, stock: i32) -> Self {
|
||||
self.stock = Some(stock);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_limited(mut self, is_limited: bool) -> Self {
|
||||
self.is_limited = Some(is_limited);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
|
||||
self.metadata = Some(metadata);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use super::gacha_items::{ActiveModel, GachaItemBuilder};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
|
||||
impl GachaItemBuilder {
|
||||
pub fn build(self) -> Result<ActiveModel, String> {
|
||||
let mut active_model = <ActiveModel as std::default::Default>::default();
|
||||
|
||||
if let Some(item_code) = self.item_code {
|
||||
active_model.item_code = Set(item_code);
|
||||
} else {
|
||||
return Err("Item code is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(name) = self.name {
|
||||
active_model.name = Set(name);
|
||||
} else {
|
||||
return Err("Name is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(description) = self.description {
|
||||
active_model.description = Set(description);
|
||||
} else {
|
||||
return Err("Description is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(rarity) = self.rarity {
|
||||
active_model.rarity = Set(rarity);
|
||||
} else {
|
||||
return Err("Rarity is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(type_) = self.type_ {
|
||||
active_model.type_ = Set(type_);
|
||||
} else {
|
||||
return Err("Type is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(category) = self.category {
|
||||
active_model.category = Set(category);
|
||||
} else {
|
||||
return Err("Category is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(value) = self.value {
|
||||
active_model.value = Set(value);
|
||||
} else {
|
||||
return Err("Value is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(weight) = self.weight {
|
||||
active_model.weight = Set(weight);
|
||||
} else {
|
||||
return Err("Weight is required".to_string());
|
||||
}
|
||||
|
||||
if let Some(stock) = self.stock {
|
||||
active_model.stock = Set(stock);
|
||||
}
|
||||
|
||||
if let Some(is_limited) = self.is_limited {
|
||||
active_model.is_limited = Set(is_limited);
|
||||
}
|
||||
|
||||
if let Some(metadata) = self.metadata {
|
||||
active_model.metadata = Set(Some(metadata));
|
||||
}
|
||||
|
||||
Ok(active_model)
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,50 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid; // Added Uuid import
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "gacha_rolls")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
pub gacha_id: String,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub item_id: Uuid,
|
||||
pub weight: f32,
|
||||
pub quantity: i32,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<DateTime>,
|
||||
pub updated_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::gacha_items::Entity",
|
||||
from = "Column::ItemId",
|
||||
to = "super::gacha_items::Column::Id"
|
||||
)]
|
||||
GachaItems,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::auth::users::Column::Id"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::gacha_items::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::GachaItems.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::super::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid; // Added Uuid import
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "gacha_rolls")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub user_id: Uuid,
|
||||
pub gacha_id: String,
|
||||
#[sea_orm(column_type = "Uuid")]
|
||||
pub item_id: Uuid,
|
||||
pub weight: f32,
|
||||
pub quantity: i32,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<DateTime>,
|
||||
pub updated_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::gacha_items::Entity",
|
||||
from = "Column::ItemId",
|
||||
to = "super::gacha_items::Column::Id"
|
||||
)]
|
||||
GachaItems,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::auth::users::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::auth::users::Column::Id"
|
||||
)]
|
||||
Users,
|
||||
}
|
||||
|
||||
impl Related<super::gacha_items::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::GachaItems.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::super::auth::users::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Users.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod gacha_credits;
|
||||
pub mod gacha_rolls;
|
||||
pub mod gacha_items;
|
||||
pub mod gacha_claims;
|
||||
pub mod gacha_claims;
|
||||
pub mod gacha_credits;
|
||||
pub mod gacha_items;
|
||||
pub mod gacha_items_queries;
|
||||
pub mod gacha_rolls;
|
||||
|
||||
@@ -1,72 +1,60 @@
|
||||
//! SeaORM entity definitions for Imphenia backend
|
||||
//! Provides PostgreSQL-compatible entity definitions corresponding to SurrealDB ResourceEnum
|
||||
|
||||
pub mod auth;
|
||||
pub mod gacha;
|
||||
pub mod common;
|
||||
pub mod relationships;
|
||||
pub mod schema_validation;
|
||||
pub mod examples;
|
||||
|
||||
// Re-export specific items from modules for better API clarity
|
||||
pub use auth::{
|
||||
users, mentors, roles, permissions, roles_permissions, sessions
|
||||
};
|
||||
pub use gacha::{
|
||||
gacha_items, gacha_claims, gacha_credits, gacha_rolls
|
||||
};
|
||||
pub use common::{
|
||||
ResourceEnum, PgUuid, generate_uuid, current_timestamp,
|
||||
audit_log, rate_limit, events, testimonials
|
||||
};
|
||||
pub use relationships;
|
||||
pub use schema_validation;
|
||||
pub use examples;
|
||||
|
||||
/// Initialize the SeaORM entity system
|
||||
/// Should be called once at application startup
|
||||
pub fn initialize() -> Result<(), String> {
|
||||
// Perform schema validation on initialization
|
||||
validate_schema_equivalence()?;
|
||||
|
||||
// Initialize any global utilities or configurations
|
||||
common::utils::initialize_utils();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the table name for a given ResourceEnum
|
||||
/// Provides a consistent way to access table names across the application
|
||||
pub fn get_table_name(resource: &common::enums::ResourceEnum) -> &str {
|
||||
resource.as_str()
|
||||
}
|
||||
|
||||
/// Get the schema name for all entities (default: "public")
|
||||
pub fn get_schema_name() -> &str {
|
||||
"public"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use common::enums::ResourceEnum;
|
||||
|
||||
#[test]
|
||||
fn test_table_name_resolution() {
|
||||
assert_eq!(get_table_name(&ResourceEnum::Users), "app_users");
|
||||
assert_eq!(get_table_name(&ResourceEnum::Roles), "app_roles");
|
||||
assert_eq!(get_table_name(&ResourceEnum::GachaItems), "app_gacha_items");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_schema_name() {
|
||||
assert_eq!(get_schema_name(), "public");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_initialize() {
|
||||
// This should not panic and should return Ok(())
|
||||
let result = initialize();
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
pub mod auth;
|
||||
pub mod gacha;
|
||||
pub mod common;
|
||||
pub mod relationships;
|
||||
pub mod schema_validation;
|
||||
pub mod examples;
|
||||
|
||||
pub use auth::{
|
||||
users, mentors, roles, permissions, roles_permissions, sessions
|
||||
};
|
||||
pub use gacha::{
|
||||
gacha_items, gacha_claims, gacha_credits, gacha_rolls
|
||||
};
|
||||
pub use common::{
|
||||
ResourceEnum, PgUuid, generate_uuid, current_timestamp,
|
||||
audit_log, rate_limit, events, testimonials
|
||||
};
|
||||
pub use relationships;
|
||||
pub use schema_validation;
|
||||
pub use examples;
|
||||
|
||||
pub fn initialize() -> Result<(), String> {
|
||||
validate_schema_equivalence()?;
|
||||
|
||||
common::utils::initialize_utils();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_table_name(resource: &common::enums::ResourceEnum) -> &str {
|
||||
resource.as_str()
|
||||
}
|
||||
|
||||
pub fn get_schema_name() -> &str {
|
||||
"public"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use common::enums::ResourceEnum;
|
||||
|
||||
#[test]
|
||||
fn test_table_name_resolution() {
|
||||
assert_eq!(get_table_name(&ResourceEnum::Users), "app_users");
|
||||
assert_eq!(get_table_name(&ResourceEnum::Roles), "app_roles");
|
||||
assert_eq!(get_table_name(&ResourceEnum::GachaItems), "app_gacha_items");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_schema_name() {
|
||||
assert_eq!(get_schema_name(), "public");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_initialize() {
|
||||
let result = initialize();
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,100 +1,90 @@
|
||||
//! Migration status tracking entity for database migration validation
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{Utc, DateTime};
|
||||
use uuid::Uuid;
|
||||
|
||||
// PgUuid and PgTimestamp are not used in this file, but kept for potential future use
|
||||
// use crate::seaorm::common::types::{PgUuid, PgTimestamp};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||
#[sea_orm(table_name = "app_migration_status")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub resource_type: String,
|
||||
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub status: String,
|
||||
|
||||
#[sea_orm(column_type = "Json", default = "null")]
|
||||
pub validation_results: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(column_type = "Text", default = "null")]
|
||||
pub last_error: Option<String>,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub total_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub validated_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub failed_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub skipped_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Text", default = "null")]
|
||||
pub validation_mode: Option<String>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub last_validated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "null")]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {
|
||||
// Default implementation - SeaORM will handle timestamps automatically
|
||||
}
|
||||
|
||||
/// Migration status constants
|
||||
pub mod status {
|
||||
pub const PENDING: &str = "pending";
|
||||
pub const IN_PROGRESS: &str = "in_progress";
|
||||
pub const COMPLETED: &str = "completed";
|
||||
pub const FAILED: &str = "failed";
|
||||
pub const PARTIAL: &str = "partial";
|
||||
pub const SKIPPED: &str = "skipped";
|
||||
}
|
||||
|
||||
/// Validation mode constants
|
||||
pub mod validation_mode {
|
||||
pub const FULL: &str = "full";
|
||||
pub const INCREMENTAL: &str = "incremental";
|
||||
pub const QUICK_CHECK: &str = "quick_check";
|
||||
}
|
||||
|
||||
/// Resource type constants matching ResourceEnum
|
||||
pub mod resource_type {
|
||||
pub const USERS: &str = "users";
|
||||
pub const ROLES: &str = "roles";
|
||||
pub const PERMISSIONS: &str = "permissions";
|
||||
pub const ROLES_PERMISSIONS: &str = "roles_permissions";
|
||||
pub const GACHA_ITEMS: &str = "gacha_items";
|
||||
pub const GACHA_CLAIMS: &str = "gacha_claims";
|
||||
pub const GACHA_ROLLS: &str = "gacha_rolls";
|
||||
pub const GACHA_CREDITS: &str = "gacha_credits";
|
||||
pub const NOTIFICATIONS: &str = "notifications";
|
||||
pub const AUDIT_LOG: &str = "audit_log";
|
||||
pub const SESSIONS: &str = "sessions";
|
||||
pub const OTP_CACHE: &str = "otp_cache";
|
||||
pub const USERS_CACHE: &str = "users_cache";
|
||||
pub const RATE_LIMIT: &str = "rate_limit";
|
||||
pub const TESTIMONIALS: &str = "testimonials";
|
||||
pub const MENTORS: &str = "mentors";
|
||||
pub const EVENTS: &str = "events";
|
||||
}
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)]
|
||||
#[sea_orm(table_name = "app_migration_status")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, default = "gen_random_uuid()", auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub resource_type: String,
|
||||
|
||||
#[sea_orm(column_type = "Text")]
|
||||
pub status: String,
|
||||
|
||||
#[sea_orm(column_type = "Json", default = "null")]
|
||||
pub validation_results: Option<serde_json::Value>,
|
||||
|
||||
#[sea_orm(column_type = "Text", default = "null")]
|
||||
pub last_error: Option<String>,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub total_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub validated_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub failed_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Integer", default = 0)]
|
||||
pub skipped_records: i32,
|
||||
|
||||
#[sea_orm(column_type = "Text", default = "null")]
|
||||
pub validation_mode: Option<String>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub last_validated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "now()")]
|
||||
pub updated_at: DateTime<Utc>,
|
||||
|
||||
#[sea_orm(column_type = "Timestamp", default = "null")]
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, sea_orm::EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
pub mod status {
|
||||
pub const PENDING: &str = "pending";
|
||||
pub const IN_PROGRESS: &str = "in_progress";
|
||||
pub const COMPLETED: &str = "completed";
|
||||
pub const FAILED: &str = "failed";
|
||||
pub const PARTIAL: &str = "partial";
|
||||
pub const SKIPPED: &str = "skipped";
|
||||
}
|
||||
|
||||
pub mod validation_mode {
|
||||
pub const FULL: &str = "full";
|
||||
pub const INCREMENTAL: &str = "incremental";
|
||||
pub const QUICK_CHECK: &str = "quick_check";
|
||||
}
|
||||
|
||||
pub mod resource_type {
|
||||
pub const USERS: &str = "users";
|
||||
pub const ROLES: &str = "roles";
|
||||
pub const PERMISSIONS: &str = "permissions";
|
||||
pub const ROLES_PERMISSIONS: &str = "roles_permissions";
|
||||
pub const GACHA_ITEMS: &str = "gacha_items";
|
||||
pub const GACHA_CLAIMS: &str = "gacha_claims";
|
||||
pub const GACHA_ROLLS: &str = "gacha_rolls";
|
||||
pub const GACHA_CREDITS: &str = "gacha_credits";
|
||||
pub const NOTIFICATIONS: &str = "notifications";
|
||||
pub const AUDIT_LOG: &str = "audit_log";
|
||||
pub const SESSIONS: &str = "sessions";
|
||||
pub const OTP_CACHE: &str = "otp_cache";
|
||||
pub const USERS_CACHE: &str = "users_cache";
|
||||
pub const RATE_LIMIT: &str = "rate_limit";
|
||||
pub const TESTIMONIALS: &str = "testimonials";
|
||||
pub const MENTORS: &str = "mentors";
|
||||
pub const EVENTS: &str = "events";
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
// SeaORM entity definitions for Imphenia backend
|
||||
// This module provides PostgreSQL-compatible entity definitions
|
||||
// corresponding to the SurrealDB ResourceEnum
|
||||
|
||||
pub mod auth;
|
||||
pub mod gacha;
|
||||
pub mod common;
|
||||
pub mod migration_status;
|
||||
pub mod auth;
|
||||
pub mod common;
|
||||
pub mod gacha;
|
||||
pub mod migration_status;
|
||||
|
||||
+167
-169
@@ -1,169 +1,167 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
use crate::permissions::{PermissionsQueryDto, PermissionsItemDto};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ExperienceDto {
|
||||
pub id: String,
|
||||
pub company: String,
|
||||
pub position: String,
|
||||
pub duration: String,
|
||||
pub period: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct EducationDto {
|
||||
pub id: String,
|
||||
pub institution: String,
|
||||
pub degree: String,
|
||||
pub field: String,
|
||||
pub period: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Default)]
|
||||
pub struct UserProfileExtensionDto {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_number: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_for_verification: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub birthdate: Option<String>,
|
||||
pub domicile: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub last_education: Option<String>,
|
||||
pub linkedin_url: Option<String>,
|
||||
pub github_url: Option<String>,
|
||||
pub cv_url: Option<String>,
|
||||
pub portfolio_url: Option<String>,
|
||||
pub website_url: Option<String>,
|
||||
pub twitter_url: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub skills: Option<Vec<String>>,
|
||||
pub experience: Option<Vec<ExperienceDto>>,
|
||||
pub education: Option<Vec<EducationDto>>,
|
||||
pub career_status: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Default)]
|
||||
pub struct RolesDetailQueryDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub permissions: Option<Vec<Option<PermissionsQueryDto>>>,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Default)]
|
||||
pub struct RolesDetailItemDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub is_deleted: bool,
|
||||
pub permissions: Vec<PermissionsItemDto>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
impl RolesDetailItemDto {
|
||||
pub fn from(dto: &RolesDetailQueryDto) -> Self {
|
||||
Self {
|
||||
id: dto.id.clone(),
|
||||
name: dto.name.clone(),
|
||||
is_deleted: dto.is_deleted,
|
||||
permissions: dto
|
||||
.permissions
|
||||
.as_ref()
|
||||
.unwrap_or(&vec![])
|
||||
.iter()
|
||||
.filter_map(|p| p.as_ref())
|
||||
.map(PermissionsItemDto::from)
|
||||
.collect(),
|
||||
created_at: dto.created_at.clone(),
|
||||
updated_at: dto.updated_at.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
pub struct UsersDetailQueryDto {
|
||||
pub id: String,
|
||||
pub fullname: String,
|
||||
pub legal_name: Option<String>,
|
||||
pub email: String,
|
||||
pub avatar: Option<String>,
|
||||
pub is_active: bool,
|
||||
pub is_deleted: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub profile_extension: Option<UserProfileExtensionDto>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_number: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_for_verification: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gender: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub domicile: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bio: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_education: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub linkedin_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub github_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cv_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub portfolio_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub website_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub twitter_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub skills: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub experience: Option<Vec<ExperienceDto>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub education: Option<Vec<EducationDto>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub career_status: Option<String>,
|
||||
pub password: String,
|
||||
pub role: RolesDetailQueryDto,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub mentor_id: Option<String>,
|
||||
}
|
||||
|
||||
impl UsersDetailQueryDto {
|
||||
pub fn from(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UsersDetailQueryDto {
|
||||
pub fn from_profile_extension(mut self) -> Self {
|
||||
if let Some(ext) = &self.profile_extension {
|
||||
self.phone_number = ext.phone_number.clone();
|
||||
self.phone_for_verification = ext.phone_for_verification.clone();
|
||||
self.gender = ext.gender.clone();
|
||||
self.domicile = ext.domicile.clone();
|
||||
self.bio = ext.bio.clone();
|
||||
self.last_education = ext.last_education.clone();
|
||||
self.linkedin_url = ext.linkedin_url.clone();
|
||||
self.github_url = ext.github_url.clone();
|
||||
self.cv_url = ext.cv_url.clone();
|
||||
self.portfolio_url = ext.portfolio_url.clone();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for UsersDetailQueryDto {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.id)
|
||||
}
|
||||
}
|
||||
use crate::permissions::{PermissionsItemDto, PermissionsQueryDto};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct ExperienceDto {
|
||||
pub id: String,
|
||||
pub company: String,
|
||||
pub position: String,
|
||||
pub duration: String,
|
||||
pub period: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct EducationDto {
|
||||
pub id: String,
|
||||
pub institution: String,
|
||||
pub degree: String,
|
||||
pub field: String,
|
||||
pub period: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Default)]
|
||||
pub struct UserProfileExtensionDto {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_number: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_for_verification: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub birthdate: Option<String>,
|
||||
pub domicile: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub last_education: Option<String>,
|
||||
pub linkedin_url: Option<String>,
|
||||
pub github_url: Option<String>,
|
||||
pub cv_url: Option<String>,
|
||||
pub portfolio_url: Option<String>,
|
||||
pub website_url: Option<String>,
|
||||
pub twitter_url: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub skills: Option<Vec<String>>,
|
||||
pub experience: Option<Vec<ExperienceDto>>,
|
||||
pub education: Option<Vec<EducationDto>>,
|
||||
pub career_status: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
pub struct RolesDetailQueryDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub permissions: Option<Vec<Option<PermissionsQueryDto>>>,
|
||||
pub is_deleted: bool,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Default)]
|
||||
pub struct RolesDetailItemDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub is_deleted: bool,
|
||||
pub permissions: Vec<PermissionsItemDto>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
impl RolesDetailItemDto {
|
||||
pub fn from(dto: &RolesDetailQueryDto) -> Self {
|
||||
Self {
|
||||
id: dto.id.clone(),
|
||||
name: dto.name.clone(),
|
||||
is_deleted: dto.is_deleted,
|
||||
permissions: dto
|
||||
.permissions
|
||||
.as_ref()
|
||||
.unwrap_or(&vec![])
|
||||
.iter()
|
||||
.filter_map(|p| p.as_ref())
|
||||
.map(PermissionsItemDto::from)
|
||||
.collect(),
|
||||
created_at: dto.created_at.clone(),
|
||||
updated_at: dto.updated_at.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
||||
pub struct UsersDetailQueryDto {
|
||||
pub id: String,
|
||||
pub fullname: String,
|
||||
pub legal_name: Option<String>,
|
||||
pub email: String,
|
||||
pub avatar: Option<String>,
|
||||
pub is_active: bool,
|
||||
pub is_deleted: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub profile_extension: Option<UserProfileExtensionDto>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_number: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub phone_for_verification: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gender: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub domicile: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bio: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last_education: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub linkedin_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub github_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cv_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub portfolio_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub website_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub twitter_url: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub skills: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub experience: Option<Vec<ExperienceDto>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub education: Option<Vec<EducationDto>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub career_status: Option<String>,
|
||||
pub password: String,
|
||||
pub role: RolesDetailQueryDto,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub mentor_id: Option<String>,
|
||||
}
|
||||
|
||||
impl UsersDetailQueryDto {
|
||||
pub fn from(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UsersDetailQueryDto {
|
||||
pub fn from_profile_extension(mut self) -> Self {
|
||||
if let Some(ext) = &self.profile_extension {
|
||||
self.phone_number = ext.phone_number.clone();
|
||||
self.phone_for_verification = ext.phone_for_verification.clone();
|
||||
self.gender = ext.gender.clone();
|
||||
self.domicile = ext.domicile.clone();
|
||||
self.bio = ext.bio.clone();
|
||||
self.last_education = ext.last_education.clone();
|
||||
self.linkedin_url = ext.linkedin_url.clone();
|
||||
self.github_url = ext.github_url.clone();
|
||||
self.cv_url = ext.cv_url.clone();
|
||||
self.portfolio_url = ext.portfolio_url.clone();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for UsersDetailQueryDto {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user