mirror of https://github.com/buster-so/buster.git
start of collections endpoints
This commit is contained in:
parent
e790547c2f
commit
bd2cbf781c
|
@ -0,0 +1,32 @@
|
|||
use anyhow::Result;
|
||||
use diesel::{ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::models::Collection;
|
||||
use crate::pool::get_pg_pool;
|
||||
use crate::schema::collections;
|
||||
|
||||
/// Fetches a single collection by ID that hasn't been deleted
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `id` - The UUID of the collection to fetch
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Result<Option<Collection>>` - The collection if found and not deleted
|
||||
pub async fn fetch_collection(id: &Uuid) -> Result<Option<Collection>> {
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
|
||||
let result = match collections::table
|
||||
.filter(collections::id.eq(id))
|
||||
.filter(collections::deleted_at.is_null())
|
||||
.first::<Collection>(&mut conn)
|
||||
.await
|
||||
{
|
||||
Ok(result) => Some(result),
|
||||
Err(diesel::NotFound) => None,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod metric_files;
|
||||
pub mod dashboard_files;
|
||||
pub mod collections;
|
||||
|
|
|
@ -38,7 +38,7 @@ pub async fn create_collection_handler(
|
|||
created_by: *user_id,
|
||||
updated_by: *user_id,
|
||||
deleted_at: None,
|
||||
organization_id,
|
||||
organization_id: *organization_id,
|
||||
};
|
||||
|
||||
let insert_task_user_id = *user_id;
|
||||
|
@ -97,7 +97,7 @@ pub async fn create_collection_handler(
|
|||
// Update search index
|
||||
let collection_id_for_search = collection_id;
|
||||
let collection_name = collection.name.clone();
|
||||
let organization_id_for_search = organization_id;
|
||||
let organization_id_for_search = *organization_id;
|
||||
|
||||
let collection_search_handle = tokio::spawn(async move {
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
|
@ -143,8 +143,6 @@ pub async fn create_collection_handler(
|
|||
collection,
|
||||
assets: None,
|
||||
permission: AssetPermissionRole::Owner,
|
||||
individual_permissions: None,
|
||||
team_permissions: None,
|
||||
organization_permissions: false,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -25,15 +25,6 @@ pub async fn delete_collection_handler(
|
|||
ids: Vec<Uuid>,
|
||||
) -> Result<DeleteCollectionResponse> {
|
||||
|
||||
// Filter out collections where the user only has viewer permission
|
||||
let filtered_ids_to_delete: Vec<Uuid> = ids
|
||||
.into_iter()
|
||||
.filter(|id| match roles.get(id) {
|
||||
Some(role) if *role != AssetPermissionRole::Viewer => true,
|
||||
_ => false,
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Get database connection
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
|
@ -44,7 +35,7 @@ pub async fn delete_collection_handler(
|
|||
|
||||
// Soft delete the collections
|
||||
match update(collections::table)
|
||||
.filter(collections::id.eq_any(&filtered_ids_to_delete))
|
||||
.filter(collections::id.eq_any(&ids))
|
||||
.set(collections::deleted_at.eq(Some(Utc::now())))
|
||||
.execute(&mut conn)
|
||||
.await
|
||||
|
@ -57,6 +48,6 @@ pub async fn delete_collection_handler(
|
|||
|
||||
// Return the IDs of the deleted collections
|
||||
Ok(DeleteCollectionResponse {
|
||||
ids: filtered_ids_to_delete,
|
||||
ids,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use database::{collections::fetch_collection, enums::AssetPermissionRole};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::collections::types::{CollectionState, GetCollectionRequest};
|
||||
|
@ -16,7 +17,15 @@ pub async fn get_collection_handler(
|
|||
req: GetCollectionRequest,
|
||||
) -> Result<CollectionState> {
|
||||
// Reuse the existing collection_utils function
|
||||
let collection = database::utils::collections::get_collection_by_id(user_id, &req.id).await?;
|
||||
|
||||
Ok(collection)
|
||||
let collection = match fetch_collection(&req.id).await? {
|
||||
Some(collection) => collection,
|
||||
None => return Err(anyhow!("Collection not found")),
|
||||
};
|
||||
|
||||
Ok(CollectionState {
|
||||
collection,
|
||||
assets: None,
|
||||
permission: AssetPermissionRole::Owner,
|
||||
organization_permissions: false,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
// Collections handlers module
|
||||
// mod create_collection_handler;
|
||||
// mod delete_collection_handler;
|
||||
// mod get_collection_handler;
|
||||
mod create_collection_handler;
|
||||
mod delete_collection_handler;
|
||||
mod get_collection_handler;
|
||||
mod list_collections_handler;
|
||||
mod types;
|
||||
// mod update_collection_handler;
|
||||
mod update_collection_handler;
|
||||
|
||||
// Re-export types
|
||||
pub use types::*;
|
||||
|
||||
// Re-export handlers
|
||||
// pub use create_collection_handler::create_collection_handler;
|
||||
// pub use delete_collection_handler::delete_collection_handler;
|
||||
// pub use get_collection_handler::get_collection_handler;
|
||||
pub use create_collection_handler::create_collection_handler;
|
||||
pub use delete_collection_handler::delete_collection_handler;
|
||||
pub use get_collection_handler::get_collection_handler;
|
||||
pub use list_collections_handler::list_collections_handler;
|
||||
// pub use update_collection_handler::update_collection_handler;
|
||||
pub use update_collection_handler::update_collection_handler;
|
||||
|
|
|
@ -96,17 +96,12 @@ pub struct UpdateCollectionAssetsRequest {
|
|||
pub type_: AssetType,
|
||||
}
|
||||
|
||||
// #[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
// pub struct UpdateCollectionRequest {
|
||||
// pub id: Uuid,
|
||||
// #[serde(flatten)]
|
||||
// pub collection: Option<UpdateCollectionObject>,
|
||||
// pub assets: Option<Vec<UpdateCollectionAssetsRequest>>,
|
||||
// pub team_permissions: Option<Vec<database::utils::sharing::asset_sharing::ShareWithTeamsReqObject>>,
|
||||
// pub user_permissions: Option<Vec<database::utils::sharing::asset_sharing::ShareWithUsersReqObject>>,
|
||||
// pub remove_teams: Option<Vec<Uuid>>,
|
||||
// pub remove_users: Option<Vec<Uuid>>,
|
||||
// }
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct UpdateCollectionRequest {
|
||||
pub id: Uuid,
|
||||
pub collection: Option<UpdateCollectionObject>,
|
||||
pub assets: Option<Vec<UpdateCollectionAssetsRequest>>,
|
||||
}
|
||||
|
||||
// Delete collection types
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use database::{
|
||||
enums::{AssetPermissionRole, AssetType},
|
||||
collections::fetch_collection,
|
||||
enums::AssetPermissionRole,
|
||||
models::CollectionToAsset,
|
||||
pool::get_pg_pool,
|
||||
schema::{collections, collections_to_assets},
|
||||
};
|
||||
use diesel::{dsl::not, update, AsChangeset, BoolExpressionMethods, ExpressionMethods};
|
||||
use diesel::{dsl::not, update, BoolExpressionMethods, ExpressionMethods};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use std::sync::Arc;
|
||||
use tokio;
|
||||
|
@ -58,19 +59,6 @@ pub async fn update_collection_handler(
|
|||
};
|
||||
|
||||
// Wait for all update operations to complete
|
||||
if let Some(update_collection_permissions_handle) = update_collection_permissions_handle {
|
||||
match update_collection_permissions_handle.await {
|
||||
Ok(Ok(_)) => (),
|
||||
Ok(Err(e)) => {
|
||||
tracing::error!("Error updating collection permissions: {}", e);
|
||||
return Err(anyhow!("Error updating collection permissions: {}", e));
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error updating collection permissions: {}", e);
|
||||
return Err(anyhow!("Error updating collection permissions: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(update_collection_record_handle) = update_collection_record_handle {
|
||||
match update_collection_record_handle.await {
|
||||
|
@ -101,14 +89,23 @@ pub async fn update_collection_handler(
|
|||
}
|
||||
|
||||
// Get the updated collection
|
||||
let collection = database::utils::collections::get_collection_by_id(user_id.as_ref(), &req.id).await?;
|
||||
|
||||
Ok(collection)
|
||||
let collection = match fetch_collection(&req.id).await? {
|
||||
Some(collection) => collection,
|
||||
None => return Err(anyhow!("Collection not found")),
|
||||
};
|
||||
|
||||
Ok(CollectionState {
|
||||
collection,
|
||||
assets: None,
|
||||
permission: AssetPermissionRole::Owner,
|
||||
organization_permissions: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Update collection record in the database
|
||||
///
|
||||
/// # Arguments
|
||||
/// # Arguments
|
||||
/// * `user_id` - The ID of the user updating the collection
|
||||
/// * `collection_id` - The ID of the collection to update
|
||||
/// * `collection` - The collection update object
|
||||
|
@ -176,7 +173,7 @@ async fn update_collection_record(
|
|||
let query = diesel::sql_query(
|
||||
"UPDATE asset_search
|
||||
SET content = $1, updated_at = NOW()
|
||||
WHERE asset_id = $2 AND asset_type = 'collection'"
|
||||
WHERE asset_id = $2 AND asset_type = 'collection'",
|
||||
)
|
||||
.bind::<diesel::sql_types::Text, _>(collection_name)
|
||||
.bind::<diesel::sql_types::Uuid, _>(*collection_id);
|
||||
|
@ -248,7 +245,7 @@ async fn update_collection_assets(
|
|||
updated_by: *user_id,
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
match diesel::insert_into(collections_to_assets::table)
|
||||
.values(&new_asset_records)
|
||||
.on_conflict((
|
||||
|
|
|
@ -1,44 +1,30 @@
|
|||
use axum::{
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
Json,
|
||||
};
|
||||
use handlers::collections::{create_collection_handler, CreateCollectionRequest, CollectionState};
|
||||
use axum::{extract::State, http::StatusCode, Extension, Json};
|
||||
use handlers::collections::{create_collection_handler, CollectionState, CreateCollectionRequest};
|
||||
use middleware::AuthenticatedUser;
|
||||
use uuid::Uuid;
|
||||
use database::utils::user::get_user_organization_id;
|
||||
|
||||
/// Create a new collection
|
||||
///
|
||||
/// This endpoint creates a new collection with the provided details.
|
||||
pub async fn create_collection(
|
||||
user: AuthenticatedUser,
|
||||
Extension(user): Extension<AuthenticatedUser>,
|
||||
Json(req): Json<CreateCollectionRequest>,
|
||||
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
||||
// Get the user's organization ID
|
||||
let org_id = match get_user_organization_id(&user.id).await {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
tracing::error!("Error getting user organization ID: {}", e);
|
||||
return Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Error getting user organization: {}", e),
|
||||
));
|
||||
}
|
||||
let user_organization = match user.organizations.first() {
|
||||
Some(org) => org,
|
||||
None => return Err((StatusCode::NOT_FOUND, "User not found".to_string())),
|
||||
};
|
||||
|
||||
// Call the handler
|
||||
match create_collection_handler(&user.id, &org_id, req).await {
|
||||
match create_collection_handler(&user.id, &user_organization.id, req).await {
|
||||
Ok(collection) => Ok(Json(collection)),
|
||||
Err(e) => {
|
||||
tracing::error!("Error creating collection: {}", e);
|
||||
|
||||
|
||||
// Return appropriate error response based on the error
|
||||
if e.to_string().contains("permission") {
|
||||
Err((
|
||||
StatusCode::FORBIDDEN,
|
||||
format!("Permission denied: {}", e),
|
||||
))
|
||||
Err((StatusCode::FORBIDDEN, format!("Permission denied: {}", e)))
|
||||
} else {
|
||||
Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use axum::{
|
||||
http::StatusCode,
|
||||
Json,
|
||||
use axum::{http::StatusCode, Extension, Json};
|
||||
use handlers::collections::{
|
||||
delete_collection_handler, DeleteCollectionRequest, DeleteCollectionResponse,
|
||||
};
|
||||
use handlers::collections::{delete_collection_handler, DeleteCollectionRequest, DeleteCollectionResponse};
|
||||
use middleware::AuthenticatedUser;
|
||||
use uuid::Uuid;
|
||||
use database::utils::user::get_user_organization_id;
|
||||
|
||||
/// Delete a collection
|
||||
///
|
||||
|
@ -14,12 +12,17 @@ pub async fn delete_collection(
|
|||
Extension(user): Extension<AuthenticatedUser>,
|
||||
Json(req): Json<DeleteCollectionRequest>,
|
||||
) -> Result<Json<DeleteCollectionResponse>, (StatusCode, String)> {
|
||||
let user_organization = match user.organizations.first() {
|
||||
Some(org) => org,
|
||||
None => return Err((StatusCode::NOT_FOUND, "User not found".to_string())),
|
||||
};
|
||||
|
||||
// Call the handler
|
||||
match delete_collection_handler(&user.id, &user.organization_id, req.ids).await {
|
||||
match delete_collection_handler(&user.id, &user_organization.id, req.ids).await {
|
||||
Ok(response) => Ok(Json(response)),
|
||||
Err(e) => {
|
||||
tracing::error!("Error deleting collection: {}", e);
|
||||
|
||||
|
||||
// Return appropriate error response based on the error
|
||||
if e.to_string().contains("not found") {
|
||||
Err((
|
||||
|
@ -27,10 +30,7 @@ pub async fn delete_collection(
|
|||
format!("Collection not found: {}", e),
|
||||
))
|
||||
} else if e.to_string().contains("permission") {
|
||||
Err((
|
||||
StatusCode::FORBIDDEN,
|
||||
format!("Permission denied: {}", e),
|
||||
))
|
||||
Err((StatusCode::FORBIDDEN, format!("Permission denied: {}", e)))
|
||||
} else {
|
||||
Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
use axum::{
|
||||
extract::{Path, State},
|
||||
extract::Path,
|
||||
http::StatusCode,
|
||||
Json,
|
||||
Extension, Json,
|
||||
};
|
||||
use handlers::collections::{get_collection_handler, CollectionState};
|
||||
use handlers::collections::{get_collection_handler, CollectionState, GetCollectionRequest};
|
||||
use middleware::AuthenticatedUser;
|
||||
use uuid::Uuid;
|
||||
use axum::extract::Extension;
|
||||
|
||||
/// Get a collection by ID
|
||||
///
|
||||
|
@ -15,8 +14,10 @@ pub async fn get_collection(
|
|||
Extension(user): Extension<AuthenticatedUser>,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
||||
let request = GetCollectionRequest { id };
|
||||
|
||||
// Call the handler
|
||||
match get_collection_handler(&user.id, &id).await {
|
||||
match get_collection_handler(&user.id, request).await {
|
||||
Ok(collection) => Ok(Json(collection)),
|
||||
Err(e) => {
|
||||
tracing::error!("Error getting collection: {}", e);
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use axum::{
|
||||
routing::get,
|
||||
routing::{get, post, put, delete},
|
||||
Router,
|
||||
};
|
||||
|
||||
mod list_collections;
|
||||
// mod get_collection;
|
||||
// mod create_collection;
|
||||
// mod update_collection;
|
||||
// mod delete_collection;
|
||||
mod get_collection;
|
||||
mod create_collection;
|
||||
mod update_collection;
|
||||
mod delete_collection;
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new()
|
||||
.route("/", get(list_collections::list_collections))
|
||||
// .route("/", post(create_collection::create_collection))
|
||||
// .route("/:id", get(get_collection::get_collection))
|
||||
// .route("/:id", put(update_collection::update_collection))
|
||||
// .route("/:id", delete(delete_collection::delete_collection))
|
||||
.route("/", post(create_collection::create_collection))
|
||||
.route("/:id", get(get_collection::get_collection))
|
||||
.route("/:id", put(update_collection::update_collection))
|
||||
.route("/:id", delete(delete_collection::delete_collection))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use axum::{
|
||||
http::StatusCode,
|
||||
Json,
|
||||
Extension, Json,
|
||||
};
|
||||
use handlers::collections::{update_collection_handler, UpdateCollectionRequest, CollectionState};
|
||||
use middleware::AuthenticatedUser;
|
||||
|
|
Loading…
Reference in New Issue