mirror of https://github.com/buster-so/buster.git
feat: add report files support to collections functionality
- Create report_files.rs helper module with permission checking - Add ReportFile asset type handling in add_assets_to_collection_handler - Add Report variant to AssetToRemove enum for removal operations - Include report files in collection queries and responses - Follow existing patterns for MetricFile and DashboardFile
This commit is contained in:
parent
ad4d7a3134
commit
41ca18ea98
|
@ -1,6 +1,7 @@
|
||||||
pub mod collections;
|
pub mod collections;
|
||||||
pub mod dashboard_files;
|
pub mod dashboard_files;
|
||||||
pub mod metric_files;
|
pub mod metric_files;
|
||||||
|
pub mod report_files;
|
||||||
pub mod chats;
|
pub mod chats;
|
||||||
pub mod organization;
|
pub mod organization;
|
||||||
pub mod test_utils;
|
pub mod test_utils;
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
use crate::enums::{AssetPermissionRole, AssetType};
|
||||||
|
use anyhow::Result;
|
||||||
|
use diesel::JoinOnDsl;
|
||||||
|
use diesel::{BoolExpressionMethods, ExpressionMethods, QueryDsl, Queryable};
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
use tokio::try_join;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::models::{AssetPermission, ReportFile};
|
||||||
|
use crate::pool::get_pg_pool;
|
||||||
|
use crate::schema::{asset_permissions, collections_to_assets, report_files};
|
||||||
|
|
||||||
|
/// Fetches a single report file by ID that hasn't been deleted
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `id` - The UUID of the report file to fetch
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Result<Option<ReportFile>>` - The report file if found and not deleted
|
||||||
|
pub async fn fetch_report_file(id: &Uuid) -> Result<Option<ReportFile>> {
|
||||||
|
let mut conn = get_pg_pool().get().await?;
|
||||||
|
|
||||||
|
let result = match report_files::table
|
||||||
|
.filter(report_files::id.eq(id))
|
||||||
|
.filter(report_files::deleted_at.is_null())
|
||||||
|
.first::<ReportFile>(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(result) => Some(result),
|
||||||
|
Err(diesel::NotFound) => None,
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch a report file by ID
|
||||||
|
async fn fetch_report(id: &Uuid) -> Result<Option<ReportFile>> {
|
||||||
|
let mut conn = get_pg_pool().get().await?;
|
||||||
|
|
||||||
|
let result = match report_files::table
|
||||||
|
.filter(report_files::id.eq(id))
|
||||||
|
.filter(report_files::deleted_at.is_null())
|
||||||
|
.first::<ReportFile>(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(result) => Some(result),
|
||||||
|
Err(diesel::NotFound) => None,
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to check if a report file is publicly accessible
|
||||||
|
async fn is_publicly_accessible(report_file: &ReportFile) -> bool {
|
||||||
|
// Check if the file is publicly accessible and either has no expiry date
|
||||||
|
// or the expiry date has not passed
|
||||||
|
report_file.publicly_accessible
|
||||||
|
&& report_file
|
||||||
|
.public_expiry_date
|
||||||
|
.map_or(true, |expiry| expiry > chrono::Utc::now())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch permission for a report file
|
||||||
|
async fn fetch_permission(id: &Uuid, user_id: &Uuid) -> Result<Option<AssetPermissionRole>> {
|
||||||
|
let mut conn = get_pg_pool().get().await?;
|
||||||
|
|
||||||
|
let permission = match asset_permissions::table
|
||||||
|
.filter(asset_permissions::asset_id.eq(id))
|
||||||
|
.filter(asset_permissions::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.filter(asset_permissions::identity_id.eq(user_id))
|
||||||
|
.filter(asset_permissions::deleted_at.is_null())
|
||||||
|
.first::<AssetPermission>(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(result) => Some(result.role),
|
||||||
|
Err(diesel::NotFound) => None,
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to fetch collection-based permissions for a report file
|
||||||
|
///
|
||||||
|
/// Checks if the user has access to the report file through collections
|
||||||
|
/// by finding collections that contain this report file and checking
|
||||||
|
/// if the user has permissions on those collections
|
||||||
|
async fn fetch_collection_permissions_for_report(
|
||||||
|
id: &Uuid,
|
||||||
|
user_id: &Uuid,
|
||||||
|
) -> Result<Option<AssetPermissionRole>> {
|
||||||
|
let mut conn = get_pg_pool().get().await?;
|
||||||
|
|
||||||
|
// Find collections containing this report file
|
||||||
|
// then join with asset_permissions to find user's permissions on those collections
|
||||||
|
let permissions = asset_permissions::table
|
||||||
|
.inner_join(
|
||||||
|
collections_to_assets::table.on(asset_permissions::asset_id
|
||||||
|
.eq(collections_to_assets::collection_id)
|
||||||
|
.and(asset_permissions::asset_type.eq(AssetType::Collection))
|
||||||
|
.and(collections_to_assets::asset_id.eq(id))
|
||||||
|
.and(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.and(collections_to_assets::deleted_at.is_null())),
|
||||||
|
)
|
||||||
|
.filter(asset_permissions::identity_id.eq(user_id))
|
||||||
|
.filter(asset_permissions::deleted_at.is_null())
|
||||||
|
.select(asset_permissions::role)
|
||||||
|
.load::<AssetPermissionRole>(&mut conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Return any collection-based permission (no need to determine highest)
|
||||||
|
if permissions.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
// Just take the first one since any collection permission is sufficient
|
||||||
|
Ok(permissions.into_iter().next())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
pub struct ReportFileWithPermission {
|
||||||
|
pub report_file: ReportFile,
|
||||||
|
pub permission: Option<AssetPermissionRole>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_report_file_with_permission(
|
||||||
|
id: &Uuid,
|
||||||
|
user_id: &Uuid,
|
||||||
|
) -> Result<Option<ReportFileWithPermission>> {
|
||||||
|
// Run all queries concurrently
|
||||||
|
let (report_file, direct_permission, collection_permission) = try_join!(
|
||||||
|
fetch_report(id),
|
||||||
|
fetch_permission(id, user_id),
|
||||||
|
fetch_collection_permissions_for_report(id, user_id)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// If the report file doesn't exist, return None
|
||||||
|
let report_file = match report_file {
|
||||||
|
Some(file) => file,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine effective permission (prioritizing collection over direct)
|
||||||
|
let effective_permission = match collection_permission {
|
||||||
|
Some(collection) => Some(collection),
|
||||||
|
None => direct_permission,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(ReportFileWithPermission {
|
||||||
|
report_file,
|
||||||
|
permission: effective_permission,
|
||||||
|
}))
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ use database::{
|
||||||
enums::{AssetPermissionRole, AssetType},
|
enums::{AssetPermissionRole, AssetType},
|
||||||
helpers::collections::fetch_collection_with_permission,
|
helpers::collections::fetch_collection_with_permission,
|
||||||
metric_files::fetch_metric_file_with_permissions,
|
metric_files::fetch_metric_file_with_permissions,
|
||||||
|
report_files::fetch_report_file_with_permission,
|
||||||
chats::fetch_chat_with_permission,
|
chats::fetch_chat_with_permission,
|
||||||
models::CollectionToAsset,
|
models::CollectionToAsset,
|
||||||
pool::get_pg_pool,
|
pool::get_pg_pool,
|
||||||
|
@ -116,12 +117,14 @@ pub async fn add_assets_to_collection_handler(
|
||||||
let mut dashboard_ids = Vec::new();
|
let mut dashboard_ids = Vec::new();
|
||||||
let mut metric_ids = Vec::new();
|
let mut metric_ids = Vec::new();
|
||||||
let mut chat_ids = Vec::new();
|
let mut chat_ids = Vec::new();
|
||||||
|
let mut report_ids = Vec::new();
|
||||||
|
|
||||||
for asset in &assets {
|
for asset in &assets {
|
||||||
match asset.asset_type {
|
match asset.asset_type {
|
||||||
AssetType::DashboardFile => dashboard_ids.push(asset.id),
|
AssetType::DashboardFile => dashboard_ids.push(asset.id),
|
||||||
AssetType::MetricFile => metric_ids.push(asset.id),
|
AssetType::MetricFile => metric_ids.push(asset.id),
|
||||||
AssetType::Chat => chat_ids.push(asset.id),
|
AssetType::Chat => chat_ids.push(asset.id),
|
||||||
|
AssetType::ReportFile => report_ids.push(asset.id),
|
||||||
_ => {
|
_ => {
|
||||||
error!(
|
error!(
|
||||||
asset_id = %asset.id,
|
asset_id = %asset.id,
|
||||||
|
@ -567,6 +570,161 @@ pub async fn add_assets_to_collection_handler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process reports
|
||||||
|
if !report_ids.is_empty() {
|
||||||
|
for report_id in &report_ids {
|
||||||
|
// Check if report exists
|
||||||
|
let report = fetch_report_file_with_permission(&report_id, &user.id).await?;
|
||||||
|
|
||||||
|
let report = if let Some(report) = report {
|
||||||
|
report
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
report_id = %report_id,
|
||||||
|
user_id = %user.id,
|
||||||
|
"Report not found"
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
*report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
"Report not found".to_string(),
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if user has access to the report
|
||||||
|
let has_report_permission = check_permission_access(
|
||||||
|
report.permission,
|
||||||
|
&[
|
||||||
|
AssetPermissionRole::CanView,
|
||||||
|
AssetPermissionRole::CanEdit,
|
||||||
|
AssetPermissionRole::FullAccess,
|
||||||
|
AssetPermissionRole::Owner,
|
||||||
|
],
|
||||||
|
report.report_file.organization_id,
|
||||||
|
&user.organizations,
|
||||||
|
report.report_file.workspace_sharing,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !has_report_permission {
|
||||||
|
error!(
|
||||||
|
report_id = %report_id,
|
||||||
|
user_id = %user.id,
|
||||||
|
"User does not have permission to access this report"
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
*report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
"Insufficient permissions".to_string(),
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the report is already in the collection
|
||||||
|
let existing = match collections_to_assets::table
|
||||||
|
.filter(collections_to_assets::collection_id.eq(collection_id))
|
||||||
|
.filter(collections_to_assets::asset_id.eq(report_id))
|
||||||
|
.filter(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.first::<CollectionToAsset>(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(record) => Some(record),
|
||||||
|
Err(diesel::NotFound) => None,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error checking if report is already in collection: {}", e);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
*report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
format!("Database error: {}", e),
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(existing_record) = existing {
|
||||||
|
if existing_record.deleted_at.is_some() {
|
||||||
|
// If it was previously deleted, update it
|
||||||
|
match diesel::update(collections_to_assets::table)
|
||||||
|
.filter(collections_to_assets::collection_id.eq(collection_id))
|
||||||
|
.filter(collections_to_assets::asset_id.eq(report_id))
|
||||||
|
.filter(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.set((
|
||||||
|
collections_to_assets::deleted_at
|
||||||
|
.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
||||||
|
collections_to_assets::updated_at.eq(chrono::Utc::now()),
|
||||||
|
collections_to_assets::updated_by.eq(user.id),
|
||||||
|
))
|
||||||
|
.execute(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
result.added_count += 1;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
collection_id = %collection_id,
|
||||||
|
report_id = %report_id,
|
||||||
|
"Error updating report in collection: {}", e
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
*report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
format!("Database error: {}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Already in the collection
|
||||||
|
info!(
|
||||||
|
collection_id = %collection_id,
|
||||||
|
report_id = %report_id,
|
||||||
|
"Report already in collection"
|
||||||
|
);
|
||||||
|
result.added_count += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add to collection
|
||||||
|
let new_record = CollectionToAsset {
|
||||||
|
collection_id: *collection_id,
|
||||||
|
asset_id: *report_id,
|
||||||
|
asset_type: AssetType::ReportFile,
|
||||||
|
created_at: chrono::Utc::now(),
|
||||||
|
created_by: user.id,
|
||||||
|
updated_at: chrono::Utc::now(),
|
||||||
|
updated_by: user.id,
|
||||||
|
deleted_at: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match diesel::insert_into(collections_to_assets::table)
|
||||||
|
.values(&new_record)
|
||||||
|
.execute(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
result.added_count += 1;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
collection_id = %collection_id,
|
||||||
|
report_id = %report_id,
|
||||||
|
"Error adding report to collection: {}", e
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
*report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
format!("Database error: {}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use database::{
|
||||||
pool::get_pg_pool,
|
pool::get_pg_pool,
|
||||||
schema::{
|
schema::{
|
||||||
asset_permissions, collections_to_assets, dashboard_files, metric_files, users,
|
asset_permissions, collections_to_assets, dashboard_files, metric_files, users,
|
||||||
chats,
|
chats, report_files,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use diesel::{ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, Queryable};
|
use diesel::{ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, Queryable};
|
||||||
|
@ -272,11 +272,39 @@ pub async fn get_collection_handler(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let report_assets_handle = tokio::spawn({
|
||||||
|
let pool = pool.clone();
|
||||||
|
let req_id = req.id;
|
||||||
|
async move {
|
||||||
|
let mut conn = pool.get().await.map_err(anyhow::Error::from)?;
|
||||||
|
collections_to_assets::table
|
||||||
|
.inner_join(report_files::table.on(report_files::id.eq(collections_to_assets::asset_id)))
|
||||||
|
.left_join(users::table.on(users::id.eq(report_files::created_by)))
|
||||||
|
.filter(collections_to_assets::collection_id.eq(req_id))
|
||||||
|
.filter(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.filter(collections_to_assets::deleted_at.is_null())
|
||||||
|
.filter(report_files::deleted_at.is_null())
|
||||||
|
.select((
|
||||||
|
report_files::id,
|
||||||
|
report_files::name,
|
||||||
|
users::name.nullable(),
|
||||||
|
users::email.nullable(),
|
||||||
|
report_files::created_at,
|
||||||
|
report_files::updated_at,
|
||||||
|
collections_to_assets::asset_type,
|
||||||
|
))
|
||||||
|
.load::<AssetQueryResult>(&mut conn)
|
||||||
|
.await
|
||||||
|
.map_err(anyhow::Error::from)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Await all tasks and handle results
|
// Await all tasks and handle results
|
||||||
let (metric_assets_result, dashboard_assets_result, chat_assets_result) = tokio::join!(
|
let (metric_assets_result, dashboard_assets_result, chat_assets_result, report_assets_result) = tokio::join!(
|
||||||
metric_assets_handle,
|
metric_assets_handle,
|
||||||
dashboard_assets_handle,
|
dashboard_assets_handle,
|
||||||
chat_assets_handle
|
chat_assets_handle,
|
||||||
|
report_assets_handle
|
||||||
);
|
);
|
||||||
|
|
||||||
// Process metric assets
|
// Process metric assets
|
||||||
|
@ -318,10 +346,23 @@ pub async fn get_collection_handler(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Process report assets
|
||||||
|
let report_assets = match report_assets_result {
|
||||||
|
Ok(Ok(assets)) => assets,
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
tracing::error!("Failed to fetch report assets: {}", e);
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("Report asset task failed: {}", e);
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// println!("dashboard_assets: {:?}", dashboard_assets); // Keep or remove debug print?
|
// println!("dashboard_assets: {:?}", dashboard_assets); // Keep or remove debug print?
|
||||||
|
|
||||||
// Combine all assets
|
// Combine all assets
|
||||||
let all_assets = [metric_assets, dashboard_assets, chat_assets].concat(); // Add chat_assets
|
let all_assets = [metric_assets, dashboard_assets, chat_assets, report_assets].concat();
|
||||||
let formatted_assets = format_assets(all_assets);
|
let formatted_assets = format_assets(all_assets);
|
||||||
|
|
||||||
// Get workspace sharing enabled by email if set
|
// Get workspace sharing enabled by email if set
|
||||||
|
|
|
@ -20,6 +20,8 @@ pub enum AssetToRemove {
|
||||||
Dashboard(Uuid),
|
Dashboard(Uuid),
|
||||||
/// Metric ID to remove
|
/// Metric ID to remove
|
||||||
Metric(Uuid),
|
Metric(Uuid),
|
||||||
|
/// Report ID to remove
|
||||||
|
Report(Uuid),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of removing assets from a collection
|
/// Result of removing assets from a collection
|
||||||
|
@ -246,6 +248,74 @@ pub async fn remove_assets_from_collection_handler(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AssetToRemove::Report(report_id) => {
|
||||||
|
// Check if the report is in the collection
|
||||||
|
let existing = match collections_to_assets::table
|
||||||
|
.filter(collections_to_assets::collection_id.eq(collection_id))
|
||||||
|
.filter(collections_to_assets::asset_id.eq(report_id))
|
||||||
|
.filter(collections_to_assets::asset_type.eq(AssetType::ReportFile))
|
||||||
|
.filter(collections_to_assets::deleted_at.is_null())
|
||||||
|
.first::<CollectionToAsset>(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(record) => Some(record),
|
||||||
|
Err(diesel::NotFound) => None,
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Error checking if report is in collection: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
format!("Database error: {}", e),
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(existing_record) = existing {
|
||||||
|
// Soft delete the record
|
||||||
|
match diesel::update(collections_to_assets::table)
|
||||||
|
.filter(collections_to_assets::collection_id.eq(existing_record.collection_id))
|
||||||
|
.filter(collections_to_assets::asset_id.eq(existing_record.asset_id))
|
||||||
|
.filter(collections_to_assets::asset_type.eq(existing_record.asset_type))
|
||||||
|
.set((
|
||||||
|
collections_to_assets::deleted_at.eq(chrono::Utc::now()),
|
||||||
|
collections_to_assets::updated_at.eq(chrono::Utc::now()),
|
||||||
|
collections_to_assets::updated_by.eq(user.id),
|
||||||
|
))
|
||||||
|
.execute(&mut conn)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
result.removed_count += 1;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
collection_id = %collection_id,
|
||||||
|
report_id = %report_id,
|
||||||
|
"Error removing report from collection: {}", e
|
||||||
|
);
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
format!("Database error: {}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Report is not in the collection, count as failed
|
||||||
|
result.failed_count += 1;
|
||||||
|
result.failed_assets.push((
|
||||||
|
report_id,
|
||||||
|
AssetType::ReportFile,
|
||||||
|
"Report is not in the collection".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue