fix(dashboards): scope annotation-panel delete to the caller's dashboard (#14263)

This commit is contained in:
Subhra264
2026-09-08 13:16:17 +00:00
committed by GitHub
parent 5ec64ebef5
commit aa91e5f35e
3 changed files with 52 additions and 3 deletions
@@ -303,7 +303,13 @@ pub async fn delete_annotation_panels(
if panels.is_empty() {
return MetaHttpResponse::bad_request("panels cannot be empty".to_string());
}
match timed_annotations::delete_timed_annotation_panels(&timed_annotation_id, panels).await {
match timed_annotations::delete_timed_annotation_panels(
&dashboard_id,
&timed_annotation_id,
panels,
)
.await
{
Ok(_) => (StatusCode::OK, "").into_response(),
Err(e) => {
log::error!("Error deleting timed annotation panels: {e}");
+7 -1
View File
@@ -95,13 +95,19 @@ pub async fn update_timed_annotations(
#[tracing::instrument]
pub async fn delete_timed_annotation_panels(
dashboard_id: &str,
timed_annotation_id: &str,
panels: Vec<String>,
) -> Result<(), anyhow::Error> {
if panels.is_empty() {
return Err(anyhow::anyhow!("panels cannot be empty"));
}
table::timed_annotation_panels::delete_many_panels(timed_annotation_id, panels.clone()).await?;
table::timed_annotation_panels::delete_many_panels_in_dashboard(
dashboard_id,
timed_annotation_id,
panels.clone(),
)
.await?;
#[cfg(feature = "enterprise")]
super_cluster::emit_timed_annotation_panels_delete_event(timed_annotation_id, panels).await?;
+38 -1
View File
@@ -16,7 +16,7 @@
use config::ider;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, Set, TransactionTrait};
use super::entity::timed_annotation_panels;
use super::entity::{dashboards, timed_annotation_panels, timed_annotations};
use crate::{
db::{get_orm_client_ro, get_orm_client_rw},
errors,
@@ -62,6 +62,8 @@ pub async fn insert_many_panels(
Ok(())
}
/// Unscoped: only for replaying a delete the originating cluster already authorized. Callers
/// serving a user request must use [`delete_many_panels_in_dashboard`].
pub async fn delete_many_panels(
timed_annotation_id: &str,
panel_ids: Vec<String>,
@@ -83,3 +85,38 @@ pub async fn delete_many_panels(
Ok(())
}
/// Removes panel associations only when the annotation belongs to the given dashboard.
pub async fn delete_many_panels_in_dashboard(
dashboard_id: &str,
timed_annotation_id: &str,
panel_ids: Vec<String>,
) -> Result<(), errors::Error> {
if panel_ids.is_empty() {
return Ok(());
}
let client = get_orm_client_rw().await;
let dashboard_record = dashboards::Entity::find()
.filter(dashboards::Column::DashboardId.eq(dashboard_id))
.one(client)
.await?
.ok_or_else(|| {
errors::Error::DbError(errors::DbError::KeyNotExists(format!(
"Dashboard '{dashboard_id}' not found"
)))
})?;
timed_annotations::Entity::find()
.filter(timed_annotations::Column::Id.eq(timed_annotation_id))
.filter(timed_annotations::Column::DashboardId.eq(dashboard_record.id))
.one(client)
.await?
.ok_or_else(|| {
errors::Error::DbError(errors::DbError::KeyNotExists(format!(
"TimedAnnotation with ID {timed_annotation_id} not found in dashboard {dashboard_id}"
)))
})?;
delete_many_panels(timed_annotation_id, panel_ids).await
}