@@ -99,20 +99,77 @@ pub async fn get_dashboard_stats(
9999 UserRole :: TenantUser => {
100100 let tenant_id = session. tenant_id . unwrap_or_default ( ) ;
101101
102- let catalogs = store. list_catalogs ( tenant_id) . await
102+ // Fetch user permissions for filtering
103+ let permissions = store. list_user_permissions ( session. user_id ) . await
103104 . map_err ( ApiError :: from) ?;
104105
105- // For now, users verify all counts in tenant.
106- // TODO: In future, filter by permissions if needed, but count_assets provides O(1) stats.
107- let namespaces_count = store. count_namespaces ( tenant_id) . await . unwrap_or ( 0 ) ;
108- let tables_count = store. count_assets ( tenant_id) . await . unwrap_or ( 0 ) ;
106+ // Get all catalogs and filter by permissions
107+ let all_catalogs = store. list_catalogs ( tenant_id) . await
108+ . map_err ( ApiError :: from) ?;
109+ let accessible_catalogs = crate :: authz_utils:: filter_catalogs (
110+ all_catalogs,
111+ & permissions,
112+ session. role . clone ( )
113+ ) ;
114+
115+ // Get all warehouses and filter by permissions
116+ // Note: Warehouses don't have direct permission scopes, so we show warehouses
117+ // associated with accessible catalogs
118+ let all_warehouses = store. list_warehouses ( tenant_id) . await
119+ . map_err ( ApiError :: from) ?;
120+ let accessible_warehouse_names: std:: collections:: HashSet < _ > = accessible_catalogs
121+ . iter ( )
122+ . filter_map ( |c| c. warehouse_name . clone ( ) )
123+ . collect ( ) ;
124+ let accessible_warehouses_count = all_warehouses
125+ . iter ( )
126+ . filter ( |w| accessible_warehouse_names. contains ( & w. name ) )
127+ . count ( ) ;
128+
129+ // Count accessible namespaces
130+ // Fetch all namespaces and filter by permissions
131+ let catalog_id_map: std:: collections:: HashMap < _ , _ > = accessible_catalogs
132+ . iter ( )
133+ . map ( |c| ( c. name . clone ( ) , c. id ) )
134+ . collect ( ) ;
135+
136+ let mut accessible_namespaces_count = 0 ;
137+ for catalog in & accessible_catalogs {
138+ if let Ok ( namespaces) = store. list_namespaces ( tenant_id, & catalog. name , None ) . await {
139+ let namespace_tuples: Vec < _ > = namespaces
140+ . into_iter ( )
141+ . map ( |ns| ( ns, catalog. name . clone ( ) ) )
142+ . collect ( ) ;
143+
144+ let filtered = crate :: authz_utils:: filter_namespaces (
145+ namespace_tuples,
146+ & permissions,
147+ session. role . clone ( ) ,
148+ & catalog_id_map
149+ ) ;
150+ accessible_namespaces_count += filtered. len ( ) ;
151+ }
152+ }
153+
154+ // Count accessible tables/assets
155+ // This is more expensive but necessary for accurate counts
156+ let mut accessible_tables_count = 0 ;
157+ if let Ok ( all_assets) = store. search_assets ( tenant_id, "" , None ) . await {
158+ let filtered_assets = crate :: authz_utils:: filter_assets (
159+ all_assets,
160+ & permissions,
161+ session. role . clone ( ) ,
162+ & catalog_id_map
163+ ) ;
164+ accessible_tables_count = filtered_assets. len ( ) ;
165+ }
109166
110167 let stats = DashboardStats {
111- catalogs_count : catalogs . len ( ) ,
112- tables_count,
113- namespaces_count,
168+ catalogs_count : accessible_catalogs . len ( ) ,
169+ tables_count : accessible_tables_count ,
170+ namespaces_count : accessible_namespaces_count ,
114171 users_count : 0 ,
115- warehouses_count : 0 ,
172+ warehouses_count : accessible_warehouses_count ,
116173 branches_count : 0 ,
117174 scope : "user" . to_string ( ) ,
118175 } ;
0 commit comments