diff --git a/Cargo.toml b/Cargo.toml index 773c28e..c54a218 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [workspace] resolver = "2" -members = [ +members = [ "tests", - "imphnen-iam", - "imphnen-cms", - "imphnen-libs", - "imphnen-utils", - "imphnen-gacha", - "imphnen-gateway", - "imphnen-backend", - "imphnen-entities", - "imphnen-dimentorin", - "imphnen-middleware", + "imphnen-entities", # Most basic - core data structures + "imphnen-libs", # Depends on entities + "imphnen-utils", # Depends on libs and entities + "imphnen-middleware",# Utility for permissions + "imphnen-iam", # Core auth service, depends on libs, utils, entities + "imphnen-cms", # Content management, depends on core services + "imphnen-gacha", # Game mechanics, depends on core services + "imphnen-dimentorin",# Learning platform, depends on core services + "imphnen-gateway", # API gateway, depends on all services + "imphnen-backend", # Main application, depends on all services ] diff --git a/imphnen-backend/src/bin/seed_roles_permissions.rs b/imphnen-backend/src/bin/seed_roles_permissions.rs index c071460..dea3f7a 100644 --- a/imphnen-backend/src/bin/seed_roles_permissions.rs +++ b/imphnen-backend/src/bin/seed_roles_permissions.rs @@ -127,7 +127,7 @@ async fn main() -> Result<(), Box> { for (role_id, permissions) in roles_permissions { let permission_refs: Vec<_> = permissions .iter() - .map(|perm| make_thing("app_permissions", perm.id())) + .map(|perm| make_thing("app_permissions", &perm.id())) .collect(); db.query("UPDATE type::thing('app_roles', $role_id) SET permissions = $permissions, updated_at = $updated_at WHERE is_deleted = false") diff --git a/imphnen-iam/src/v1/permissions/permissions_enum.rs b/imphnen-iam/src/v1/permissions/permissions_enum.rs index c37f778..2ccbeb9 100644 --- a/imphnen-iam/src/v1/permissions/permissions_enum.rs +++ b/imphnen-iam/src/v1/permissions/permissions_enum.rs @@ -1,27 +1,36 @@ use std::fmt; - +use uuid::Uuid; use strum_macros::EnumIter; #[derive(Debug, Clone, PartialEq, Eq, 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, + + // Team permissions ReadListTeams, ReadDetailTeams, + + // Gacha permissions CreateGachaClaims, ReadDetailGachaClaims, ReadListGachaItems, @@ -33,6 +42,8 @@ pub enum PermissionsEnum { CreateGachaRolls, ExecuteGachaRolls, DeleteGachaRolls, + + // Mentor permissions ReadListMentors, ReadDetailMentors, RegisterMentors, @@ -47,22 +58,33 @@ pub enum PermissionsEnum { 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", + + // Team permissions + PermissionsEnum::ReadListTeams => "Read List Teams", + PermissionsEnum::ReadDetailTeams => "Read Detail Teams", + + // Gacha permissions PermissionsEnum::CreateGachaClaims => "Create Gacha Claims", PermissionsEnum::ReadDetailGachaClaims => "Read Detail Gacha Claims", PermissionsEnum::ReadListGachaItems => "Read List Gacha Items", @@ -74,6 +96,8 @@ impl fmt::Display for PermissionsEnum { 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", @@ -89,58 +113,117 @@ impl fmt::Display for PermissionsEnum { } impl PermissionsEnum { - pub fn id(&self) -> &'static str { + pub fn id(&self) -> String { match self { - PermissionsEnum::ReadListUsers => "7c15e31d-36e2-49f9-97db-138c03fb0cf6", - PermissionsEnum::ReadDetailUsers => "319ee593-ff0a-4f29-bbaf-9feb3174a3a6", - PermissionsEnum::CreateUsers => "023e2dfe-93c3-4008-94a8-b5dff403f73b", - PermissionsEnum::DeleteUsers => "96df0689-2ae9-4894-bf00-837c19415e5c", - PermissionsEnum::UpdateUsers => "98b3dc4c-0124-461f-afcd-166637c5e6e8", - PermissionsEnum::ActivateUsers => "4da8b434-89f9-4d91-85ae-eebd63cdbeda", - PermissionsEnum::ReadListRoles => "9164ca6e-c7e3-4238-a15f-f36ab9577e7e", - PermissionsEnum::ReadDetailRoles => "73888d18-b3e9-4f62-95a5-ba2c0d69fccb", - PermissionsEnum::CreateRoles => "319ee593-ff0a-4f29-bbaf-9feb3174a3a2", - PermissionsEnum::DeleteRoles => "35b0d992-65c8-4b62-b030-e6e0320e4048", - PermissionsEnum::UpdateRoles => "a00d5608-4c48-4542-845c-dfe004687022", - PermissionsEnum::ReadListPermissions => "8195eeb8-e64f-4172-aa57-596492c84a72", - PermissionsEnum::ReadDetailPermissions => { - "dad435cf-042c-41bd-a946-cea61ed2ffbc" - } - PermissionsEnum::CreatePermissions => "0269ed71-0ae0-4c43-ad29-e3d861d8f9a0", - PermissionsEnum::DeletePermissions => "b2dc3928-86ba-4c59-a03d-0b57d5183ebc", - PermissionsEnum::UpdatePermissions => "299cb4d5-6556-4cc9-b6c1-32e6d31e0f9b", - PermissionsEnum::CreateGachaClaims => "f41d53ce-4f88-4bb6-b9b4-5e3a8c38d962", - PermissionsEnum::ReadDetailGachaClaims => { - "c1c3d6c2-19fb-4b70-b58c-c19f2e8cfc79" - } - PermissionsEnum::ReadListGachaItems => "fa6eb842-0a61-40c2-9c24-b226ad975037", - PermissionsEnum::ReadDetailGachaItems => { - "9c7857d7-b5ae-4688-923d-ef5572e9bc8b" - } - PermissionsEnum::CreateGachaItems => "cf063be1-4d71-489e-b9fb-1c08c65f396c", - PermissionsEnum::DeleteGachaItems => "46f8c6cf-ea0c-4c90-860c-69e2e65f7eb1", - PermissionsEnum::UpdateGachaItems => "2d0cf4ae-56ae-4714-a12e-655cfc3d9eb2", - PermissionsEnum::ReadDetailGachaRolls => { - "53d6483a-04cd-4667-8792-2d0cc8e2d343" - } - PermissionsEnum::CreateGachaRolls => "18e36c63-fcb7-4877-b911-c5aa611e878f", - PermissionsEnum::ExecuteGachaRolls => "14c6a1cd-5c63-4643-89b5-b1a5f9920cc0", - PermissionsEnum::DeleteGachaRolls => "12345678-ABCD-EFAB-CDEF-0123456789AB", - PermissionsEnum::ReadListMentors => "a1b2c3d4-5e6f-7890-abcd-ef1234567890", - PermissionsEnum::ReadDetailMentors => "b2c3d4e5-6f78-9012-bcde-f23456789012", - PermissionsEnum::ReadListTeams => "e1f2g3h4-5i6j-7k8l-9m0n-op1q2r3s4t5u", - PermissionsEnum::ReadDetailTeams => "f2g3h4i5-6j7k-8l9m-0n1o-pq2r3s4t5u6", - PermissionsEnum::RegisterMentors => "c3d4e5f6-7890-1234-cdef-345678901234", - PermissionsEnum::ReadOwnMentorProfile => { - "d4e5f6a7-8901-2345-def0-456789012345" - } - PermissionsEnum::UpdateOwnMentorProfile => { - "e5f6a7b8-9012-3456-ef01-567890123456" - } - PermissionsEnum::ReadOwnMentorStatus => "f6a7b8c9-0123-4567-f012-678901234567", - PermissionsEnum::UpdateMentors => "a7b8c9d0-1234-5678-0123-789012345678", - PermissionsEnum::VerifyMentors => "b8c9d0e1-2345-6789-1234-890123456789", - PermissionsEnum::DeleteMentors => "c9d0e1f2-3456-7890-2345-901234567890", + // 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(), + + // Team permissions + PermissionsEnum::ReadListTeams => "e1f23456-7890-1234-5678-90abcdef1234".to_string(), + PermissionsEnum::ReadDetailTeams => "f2345678-8901-2345-6789-01bcdef23456".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(), } } + + /// 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 { + 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, + + // Team permissions + PermissionsEnum::ReadListTeams, + PermissionsEnum::ReadDetailTeams, + + // 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, + ] + } } diff --git a/imphnen-iam/src/v1/roles/roles_enum.rs b/imphnen-iam/src/v1/roles/roles_enum.rs index 5b43c09..c2c3332 100644 --- a/imphnen-iam/src/v1/roles/roles_enum.rs +++ b/imphnen-iam/src/v1/roles/roles_enum.rs @@ -3,6 +3,7 @@ use std::fmt; #[derive(Debug, Clone, PartialEq, Eq)] pub enum RolesEnum { Admin, + Administrator, // Added Administrator role User, Staff, Mentor, // Added Mentor role @@ -12,6 +13,7 @@ impl fmt::Display for RolesEnum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let roles_str = match self { RolesEnum::Admin => "Admin", + RolesEnum::Administrator => "Administrator", // Added Administrator role RolesEnum::User => "User", RolesEnum::Staff => "Staff", RolesEnum::Mentor => "Mentor", // Added Mentor role diff --git a/imphnen-iam/src/v1/teams/mod.rs b/imphnen-iam/src/v1/teams/mod.rs index 577abc7..d01a872 100644 --- a/imphnen-iam/src/v1/teams/mod.rs +++ b/imphnen-iam/src/v1/teams/mod.rs @@ -10,21 +10,8 @@ pub use teams_repository::*; pub use teams_schema::*; pub use teams_service::*; -use axum::{ - routing::{delete, get, post, put}, - Router, -}; +use axum::Router; pub fn teams_router() -> Router { Router::new() - .route("/", get(get_team_list)) - .route("/create", post(post_create_team)) - .route("/detail/{id}", get(get_team_by_id)) - .route("/update/{id}", put(put_update_team)) - .route("/delete/{id}", delete(delete_team)) - .route("/{id}/invite", post(post_invite_team_members)) - .route("/accept/{token}", post(post_accept_invitation)) - .route("/search", get(get_public_team_search)) - .route("/{id}/members", get(get_team_members)) - .route("/{id}/leave", post(post_leave_team)) } \ No newline at end of file diff --git a/imphnen-iam/src/v1/teams/teams_controller.rs b/imphnen-iam/src/v1/teams/teams_controller.rs index 05479de..3d9eb0c 100644 --- a/imphnen-iam/src/v1/teams/teams_controller.rs +++ b/imphnen-iam/src/v1/teams/teams_controller.rs @@ -6,9 +6,7 @@ use crate::{ TeamMemberDto, TeamsSearchQueryDto, PublicTeamsListItemDto, PublicTeamsDetailItemDto, AdminTeamsListItemDto, AdminTeamsDetailItemDto, PermissionsEnum }; -use axum::http::StatusCode; use axum::response::Response; -use axum::extract::Query; use axum::extract::Path; use axum::http::HeaderMap; use axum::response::IntoResponse; @@ -20,10 +18,10 @@ async fn authenticated( headers: HeaderMap, state: Extension, f: F, -) -> impl IntoResponse +) -> Response where F: FnOnce(crate::Claims, AppState) -> Fut, - Fut: std::future::Future + Send, + Fut: std::future::Future + Send, { match permissions_guard(headers, state, vec![]).await { Ok((claims, state)) => f(claims, state).await, @@ -35,12 +33,12 @@ where async fn with_perms( headers: HeaderMap, state: Extension, - perms: Vec, + perms: Vec, f: F, -) -> impl IntoResponse +) -> Response where F: FnOnce(crate::Claims, AppState) -> Fut, - Fut: std::future::Future + Send, + Fut: std::future::Future + Send, { match permissions_guard(headers, state, perms).await { Ok((claims, state)) => f(claims, state).await, @@ -73,14 +71,11 @@ pub async fn get_team_list( headers: Option, Extension(state): Extension, axum::extract::Query(meta): axum::extract::Query, -) -> impl IntoResponse { +) -> Response { + let state = state; match headers { Some(headers) => { - match permissions_guard( - headers, - Extension(state.clone()), - vec![], - ).await { + match permissions_guard(headers, axum::Extension(state.clone()), vec![]).await { Ok((_claims, state)) => TeamsService::get_team_list(&state, meta).await, Err(_) => TeamsService::get_public_team_list(&state, meta).await, } @@ -105,14 +100,11 @@ pub async fn get_team_by_id( headers: Option, Extension(state): Extension, Path(id): Path, -) -> impl IntoResponse { +) -> Response { + let state = state; match headers { Some(headers) => { - match permissions_guard( - headers, - Extension(state.clone()), - vec![], - ).await { + match permissions_guard(headers, axum::Extension(state.clone()), vec![]).await { Ok((_claims, state)) => TeamsService::get_team_by_id(&state, id).await, Err(_) => TeamsService::get_public_team_by_id(&state, id).await, } @@ -343,8 +335,12 @@ pub async fn get_admin_team_list( headers: HeaderMap, Extension(state): Extension, axum::extract::Query(meta): axum::extract::Query, -) -> impl IntoResponse { - with_perms(headers, Extension(state), vec![PermissionsEnum::ReadListTeams.to_string()], move |_claims, state| TeamsService::get_admin_team_list(&state, meta)).await +) -> Response { + let state = state; + with_perms(headers, axum::Extension(state), vec![PermissionsEnum::ReadListTeams], move |_claims, state| { + let response = TeamsService::get_admin_team_list(&state, meta); + response + }).await } #[utoipa::path( @@ -365,8 +361,12 @@ pub async fn get_admin_team_by_id( headers: HeaderMap, Extension(state): Extension, Path(id): Path, -) -> impl IntoResponse { - with_perms(headers, Extension(state), vec![PermissionsEnum::ReadDetailTeams.to_string()], move |_claims, state| TeamsService::get_admin_team_by_id(&state, id)).await +) -> Response { + let state = state; + with_perms(headers, axum::Extension(state), vec![PermissionsEnum::ReadDetailTeams], move |_claims, state| { + let response = TeamsService::get_admin_team_by_id(&state, id); + response + }).await } #[utoipa::path( @@ -387,6 +387,10 @@ pub async fn get_admin_team_members( headers: HeaderMap, Extension(state): Extension, Path(id): Path, -) -> impl IntoResponse { - with_perms(headers, Extension(state), vec![PermissionsEnum::ReadDetailTeams.to_string()], move |_claims, state| TeamsService::get_admin_team_members(&state, id)).await +) -> Response { + let state = state; + with_perms(headers, axum::Extension(state), vec![PermissionsEnum::ReadDetailTeams], move |_claims, state| { + let response = TeamsService::get_admin_team_members(&state, id); + response + }).await } diff --git a/imphnen-iam/src/v1/teams/teams_dto.rs b/imphnen-iam/src/v1/teams/teams_dto.rs index b2fc926..34f4d1c 100644 --- a/imphnen-iam/src/v1/teams/teams_dto.rs +++ b/imphnen-iam/src/v1/teams/teams_dto.rs @@ -325,6 +325,32 @@ impl TeamsDetailQueryDto { } } +impl TeamsListItemDto { + pub fn into_list_item_dto(self) -> Self { + self + } + + pub fn into_admin_list_dto(self) -> AdminTeamsListItemDto { + AdminTeamsListItemDto { + id: self.id, + name: self.name, + description: self.description, + leader: self.leader, + is_open: self.is_open, + current_member_count: self.current_member_count, + max_members: self.max_members, + skills_required: self.skills_required, + location: self.location, + avatar: self.avatar, + website_url: None, + github_url: None, + is_active: true, + is_deleted: false, + created_at: self.created_at, + } + } +} + impl TeamsListQueryDto { pub fn into_list_item_dto(self) -> TeamsListItemDto { TeamsListItemDto { diff --git a/imphnen-iam/src/v1/teams/teams_repository.rs b/imphnen-iam/src/v1/teams/teams_repository.rs index 5b9a565..7953cec 100644 --- a/imphnen-iam/src/v1/teams/teams_repository.rs +++ b/imphnen-iam/src/v1/teams/teams_repository.rs @@ -8,8 +8,7 @@ use imphnen_libs::{ }; use imphnen_utils::{ get_id, DetailQueryBuilder, QueryListBuilder, make_thing_from_enum, - build_thing_condition, build_multi_thing_condition, execute_safe_update_query, execute_safe_count_query, - ListQueryBuilder + build_multi_thing_condition, execute_safe_update_query, execute_safe_count_query, }; use surrealdb::sql::Thing; use anyhow::{Result, bail}; @@ -52,7 +51,7 @@ impl<'a> TeamsRepository<'a> { let data = result .data .into_iter() - .map(TeamsListQueryDto::from) + .map(|dto| dto.into_list_item_dto()) .collect(); Ok(ResponseListSuccessDto { data, @@ -215,7 +214,7 @@ impl<'a> TeamsRepository<'a> { Ok(members) } - pub async fn query_user_teams(&self, user_id: &Thing) -> Result> { + pub async fn query_teams_by_user(&self, user_id: &Thing) -> Result> { let now = Instant::now(); let db = &self.state.surrealdb_ws; let sql = format!( @@ -390,7 +389,7 @@ impl<'a> TeamsRepository<'a> { let data = result .data .into_iter() - .map(TeamsListQueryDto::from) + .map(|dto| dto.into_list_item_dto()) .collect(); Ok(ResponseListSuccessDto { data, diff --git a/imphnen-iam/src/v1/teams/teams_service.rs b/imphnen-iam/src/v1/teams/teams_service.rs index 7ab4cc8..5b5046f 100644 --- a/imphnen-iam/src/v1/teams/teams_service.rs +++ b/imphnen-iam/src/v1/teams/teams_service.rs @@ -2,8 +2,7 @@ use super::{ TeamsCreateRequestDto, TeamsUpdateRequestDto, TeamInviteRequestDto, TeamAcceptInvitationRequestDto, TeamsDetailItemDto, MemberTeamsDetailItemDto, TeamMemberDto, TeamsRepository, TeamsSchema, TeamMembersSchema, - TeamInvitationsSchema, TeamsSearchQueryDto, PublicTeamsListItemDto, PublicTeamsDetailItemDto, - AdminTeamsListItemDto, AdminTeamsDetailItemDto + TeamInvitationsSchema, TeamsSearchQueryDto, PublicTeamsDetailItemDto, AdminTeamsListItemDto }; use crate::{ AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto, @@ -137,6 +136,7 @@ impl TeamsServiceTrait for TeamsService { match repo.query_team_by_id(&thing_id).await { Ok(team) if !team.is_deleted => { let members = repo.query_team_members(&team.id).await.unwrap_or_default(); + let members_len = members.len(); // For public team details, only show sensitive info if user is authenticated and part of the team let team_dto = TeamsDetailItemDto { @@ -155,7 +155,7 @@ impl TeamsServiceTrait for TeamsService { }, is_open: team.is_open, max_members: team.max_members, - current_member_count: members.len() as i32 + 1, + current_member_count: members_len as i32 + 1, skills_required: team.skills_required, location: team.location, avatar: team.avatar, @@ -202,6 +202,7 @@ impl TeamsServiceTrait for TeamsService { match repo.query_team_by_id(&thing_id).await { Ok(team) if !team.is_deleted => { let members = repo.query_team_members(&team.id).await.unwrap_or_default(); + let members_len = members.len(); // For member team details, include all information including members list let mut member_dtos = Vec::new(); @@ -244,16 +245,17 @@ impl TeamsServiceTrait for TeamsService { } }; + let leader_dto_clone = leader_dto.clone(); member_dtos.insert(0, leader_dto); let team_dto = MemberTeamsDetailItemDto { id: team.id.id.to_raw(), name: team.name, description: team.description, - leader: leader_dto, + leader: leader_dto_clone, is_open: team.is_open, max_members: team.max_members, - current_member_count: members.len() as i32 + 1, + current_member_count: members_len as i32 + 1, skills_required: team.skills_required, location: team.location, avatar: team.avatar, @@ -300,6 +302,7 @@ impl TeamsServiceTrait for TeamsService { match repo.query_team_by_id(&thing_id).await { Ok(team) if !team.is_deleted => { let members = repo.query_team_members(&team.id).await.unwrap_or_default(); + let members_len = members.len(); // For public team details, only show sensitive info if user is authenticated and part of the team let team_dto = PublicTeamsDetailItemDto { @@ -308,7 +311,7 @@ impl TeamsServiceTrait for TeamsService { description: team.description, is_open: team.is_open, max_members: team.max_members, - current_member_count: members.len() as i32 + 1, + current_member_count: members_len as i32 + 1, skills_required: team.skills_required, location: team.location, avatar: team.avatar, @@ -765,21 +768,21 @@ impl TeamsServiceTrait for TeamsService { } fn get_admin_team_list(state: &AppState, meta: MetaRequestDto) -> Pin + Send>> { - let state = state.to_owned(); - Box::pin(async move { - let repo = TeamsRepository::new(&state); - match repo.query_team_list(meta).await { - Ok(data) => { - let response = ResponseListSuccessDto { - data: data.data.into_iter().map(|team| team.to_admin_list_dto()).collect(), - meta: data.meta, - }; - success_list_response(response) + let state = state.to_owned(); + Box::pin(async move { + let repo = TeamsRepository::new(&state); + match repo.query_team_list(meta).await { + Ok(data) => { + let response = ResponseListSuccessDto { + data: data.data.into_iter().map(|team| team.into_list_item_dto().into_admin_list_dto()).collect::>(), + meta: data.meta, + }; + success_list_response(response) + } + Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()), } - Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()), - } - }) - } + }) + } fn get_admin_team_by_id(state: &AppState, id: String) -> Pin + Send>> { let state = state.to_owned(); @@ -824,7 +827,7 @@ impl TeamsServiceTrait for TeamsService { Err(_) => {} } - let team_dto = team.to_admin_detail_dto(member_dtos); + let team_dto = team.into_admin_detail_dto(member_dtos); success_response(ResponseSuccessDto { data: team_dto }) } Ok(_) => common_response(StatusCode::NOT_FOUND, "Team not found"), @@ -899,7 +902,7 @@ impl TeamsServiceTrait for TeamsService { } match repo.query_remove_team_member(&team_thing, &user_thing).await { - Ok(msg) => common_response(StatusCode::OK, &format!("Successfully left team: {}", team.name)), + Ok(_) => common_response(StatusCode::OK, &format!("Successfully left team: {}", team.name)), Err(e) => { error!("Failed to remove team member: {}", e); return common_response(StatusCode::INTERNAL_SERVER_ERROR, "Failed to leave team") diff --git a/imphnen-libs/src/axum/mod.rs b/imphnen-libs/src/axum/mod.rs index 0acc815..8713a6b 100644 --- a/imphnen-libs/src/axum/mod.rs +++ b/imphnen-libs/src/axum/mod.rs @@ -22,8 +22,7 @@ where let addr = SocketAddr::from(([0, 0, 0, 0], port)); let listener = TcpListener::bind(&addr).await.unwrap(); - match serve(listener, router).await { - Ok(_) => {} - Err(_err) => {} - } + if let Err(err) = serve(listener, router).await { + log::error!("Server failed to start: {}", err); + } }