This PRD describes the modifications needed for the `get_dashboard_handler` to implement granular permission checks for each metric included in a dashboard. It involves leveraging the central permission helper and adjusting how metric data is fetched and represented in the response, potentially by modifying `get_metric_handler` or how its results are processed.
**Note on Concurrency:** This work depends on the completion of the [Refactor Sharing Permission Helper](mdc:prds/active/refactor_sharing_permission_helper.md). Once the helper is available, this task can potentially be performed concurrently with the enhancements for the collection and data execution handlers.
Currently, `get_dashboard_handler` fetches associated metrics using `get_metric_handler`. If `get_metric_handler` fails (potentially due to permissions), the metric is silently filtered out from the dashboard response's `metrics` map. Users aren't informed *why* a metric configured in the dashboard isn't visible, and they can't distinguish between a metric failing to load due to an error vs. lack of permissions.
- Ensure that if a user lacks `CanView` permission for a metric configured in a dashboard, the metric is still included in the response's `metrics` map, but represented minimally with `has_access: false`.
- Add the `has_access: bool` field to the `BusterMetric` type.
- Leverage the `check_specific_asset_access` helper for permission verification.
- **Note:** This handler modification primarily affects the *metadata* served about the metric. Blocking the actual *execution* of the metric's SQL query for data retrieval will be handled by adding permission checks to the relevant data execution handler (as per the project PRD).
- Add `has_access: bool` to `BusterMetric` struct (likely in `libs/handlers/src/metrics/types.rs`). Also ensure relevant nested types like `ChartConfig` (note: it's from `database::types::ChartConfig`) are handled during minimal object creation.
-**Initial Fetch & Check:** Start by fetching the basic `metric_files` record *and* checking permission using `check_specific_asset_access` (or `fetch_metric_file_with_permission` if it can be adapted to return the basic file even on permission denial).
```rust
// Inside get_metric_handler...
let mut conn = get_pg_pool().get().await?;
let metric_id = /* get metric_id */;
let user = /* get user */;
// Fetch basic info first (needed for permission check and minimal response)
-**Return Value:** The handler now always returns `Ok(BusterMetric)` if the metric exists, differentiating access via the `has_access` flag. It only returns `Err` if the metric record itself is not found or if a database error occurs during the permission check or data fetching.
3.**Modify `get_dashboard_handler.rs`:**
- The logic using `join_all` and collecting results into the `metrics: HashMap<Uuid, BusterMetric>` map can remain largely the same, as `get_metric_handler` will now consistently return `Ok` for existing metrics. Errors genuinely representing fetch failures (metric not found, DB error) will still be `Err` and should be logged/handled.
```rust
// In get_dashboard_handler, processing results:
let metric_results = join_all(metric_futures).await;
let metrics: HashMap<Uuid,BusterMetric> = metric_results
.into_iter()
.filter_map(|result| match result {
Ok(metric) => Some((metric.id, metric)), // metric includes has_access flag
Err(e) => {
// Log actual errors (metric not found, DB connection issues, etc.)
tracing::error!("Failed to fetch metric details for dashboard (non-permission error): {}", e);
None // Exclude metric if there was a real error
}
})
.collect();
```
**Option B: Handle in `get_dashboard_handler` (Less Recommended)**
- Keep `get_metric_handler` mostly as-is (returning `Err` on permission denied).
- In `get_dashboard_handler`, after `join_all`, iterate through results. If a result is `Err`, attempt a *separate* minimal query to fetch just the `id` and `name` for that metric ID. If successful, create a minimal `BusterMetric { has_access: false, ... }` and add it to the map. If the minimal query fails (e.g., metric truly doesn't exist), log and omit.
-*Drawback:* Less efficient (potential extra queries), splits logic.