Skip to content

Commit 8c235e0

Browse files
add query params in update dashboard
1. is_favorite=true/false -- to set dashboard to favorite 2. rename_to=<updated title> -- to update the title of the dashboard 3. tags=<comma separated tags> -- to update tags add validation - body and query params both cannot co-exist in PUT request
1 parent 87c3892 commit 8c235e0

File tree

2 files changed

+72
-23
lines changed

2 files changed

+72
-23
lines changed

src/handlers/http/users/dashboards.rs

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*
1717
*/
1818

19+
use std::collections::HashMap;
20+
1921
use crate::{
2022
handlers::http::rbac::RBACError,
2123
storage::ObjectStorageError,
@@ -68,37 +70,83 @@ pub async fn create_dashboard(
6870
pub async fn update_dashboard(
6971
req: HttpRequest,
7072
dashboard_id: Path<String>,
71-
Json(mut dashboard): Json<Dashboard>,
73+
Json(dashboard): Json<Dashboard>,
7274
) -> Result<impl Responder, DashboardError> {
7375
let user_id = get_hash(&get_user_from_request(&req)?);
7476
let dashboard_id = validate_dashboard_id(dashboard_id.into_inner())?;
77+
let mut existing_dashboard = DASHBOARDS
78+
.get_dashboard_by_user(dashboard_id, &user_id)
79+
.await
80+
.ok_or(DashboardError::Metadata(
81+
"Dashboard does not exist or user is not authorized",
82+
))?;
7583

76-
// Validate all tiles have valid IDs
77-
if let Some(tiles) = &dashboard.tiles {
78-
if tiles.iter().any(|tile| tile.tile_id.is_nil()) {
79-
return Err(DashboardError::Metadata("Tile ID must be provided"));
80-
}
84+
let query_map = web::Query::<HashMap<String, String>>::from_query(req.query_string())
85+
.map_err(|_| DashboardError::InvalidQueryParameter)?;
86+
87+
// Validate: either query params OR body, not both
88+
let has_query_params = !query_map.is_empty();
89+
let has_body_update = dashboard.title != existing_dashboard.title || dashboard.tiles.is_some();
90+
91+
if has_query_params && has_body_update {
92+
return Err(DashboardError::Metadata(
93+
"Cannot use both query parameters and request body for updates",
94+
));
8195
}
8296

83-
// Check if tile_id are unique
84-
if let Some(tiles) = &dashboard.tiles {
85-
let unique_tiles: Vec<_> = tiles
86-
.iter()
87-
.map(|tile| tile.tile_id)
88-
.collect::<std::collections::HashSet<_>>()
89-
.into_iter()
90-
.collect();
91-
92-
if unique_tiles.len() != tiles.len() {
93-
return Err(DashboardError::Metadata("Tile IDs must be unique"));
97+
let mut final_dashboard = if has_query_params {
98+
// Apply partial updates from query parameters
99+
if let Some(is_favorite) = query_map.get("is_favorite") {
100+
existing_dashboard.is_favorite = Some(is_favorite == "true");
101+
}
102+
if let Some(tags) = query_map.get("tags") {
103+
let parsed_tags: Vec<String> = tags
104+
.split(',')
105+
.map(|s| s.trim())
106+
.filter(|s| !s.is_empty())
107+
.map(|s| s.to_string())
108+
.collect();
109+
existing_dashboard.tags = if parsed_tags.is_empty() {
110+
None
111+
} else {
112+
Some(parsed_tags)
113+
};
114+
}
115+
if let Some(rename_to) = query_map.get("rename_to") {
116+
let trimmed = rename_to.trim();
117+
if trimmed.is_empty() {
118+
return Err(DashboardError::Metadata("Rename to cannot be empty"));
119+
}
120+
existing_dashboard.title = trimmed.to_string();
121+
}
122+
existing_dashboard
123+
} else {
124+
if let Some(tiles) = &dashboard.tiles {
125+
if tiles.iter().any(|tile| tile.tile_id.is_nil()) {
126+
return Err(DashboardError::Metadata("Tile ID must be provided"));
127+
}
128+
129+
// Check if tile_id are unique
130+
let unique_tiles: Vec<_> = tiles
131+
.iter()
132+
.map(|tile| tile.tile_id)
133+
.collect::<std::collections::HashSet<_>>()
134+
.into_iter()
135+
.collect();
136+
137+
if unique_tiles.len() != tiles.len() {
138+
return Err(DashboardError::Metadata("Tile IDs must be unique"));
139+
}
94140
}
95-
}
141+
142+
dashboard
143+
};
96144

97145
DASHBOARDS
98-
.update(&user_id, dashboard_id, &mut dashboard)
146+
.update(&user_id, dashboard_id, &mut final_dashboard)
99147
.await?;
100148

101-
Ok((web::Json(dashboard), StatusCode::OK))
149+
Ok((web::Json(final_dashboard), StatusCode::OK))
102150
}
103151

104152
pub async fn delete_dashboard(
@@ -164,6 +212,8 @@ pub enum DashboardError {
164212
Custom(String),
165213
#[error("Dashboard does not exist or is not accessible")]
166214
Unauthorized,
215+
#[error("Invalid query parameter")]
216+
InvalidQueryParameter,
167217
}
168218

169219
impl actix_web::ResponseError for DashboardError {
@@ -175,6 +225,7 @@ impl actix_web::ResponseError for DashboardError {
175225
Self::UserDoesNotExist(_) => StatusCode::NOT_FOUND,
176226
Self::Custom(_) => StatusCode::INTERNAL_SERVER_ERROR,
177227
Self::Unauthorized => StatusCode::UNAUTHORIZED,
228+
Self::InvalidQueryParameter => StatusCode::BAD_REQUEST,
178229
}
179230
}
180231

src/users/dashboards.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ impl Dashboard {
8383
}
8484

8585
// if is_favorite is None, set it to false, else set it to the current value
86-
self.is_favorite = Some(
87-
self.is_favorite.unwrap_or(false), // default to false if not set
88-
);
86+
self.is_favorite = self.is_favorite.or(Some(false));
8987
}
9088

9189
/// create a summary of the dashboard

0 commit comments

Comments
 (0)