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 metric_files;
|
||||||
pub mod dashboard_files;
|
pub mod dashboard_files;
|
||||||
|
pub mod collections;
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub async fn create_collection_handler(
|
||||||
created_by: *user_id,
|
created_by: *user_id,
|
||||||
updated_by: *user_id,
|
updated_by: *user_id,
|
||||||
deleted_at: None,
|
deleted_at: None,
|
||||||
organization_id,
|
organization_id: *organization_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let insert_task_user_id = *user_id;
|
let insert_task_user_id = *user_id;
|
||||||
|
@ -97,7 +97,7 @@ pub async fn create_collection_handler(
|
||||||
// Update search index
|
// Update search index
|
||||||
let collection_id_for_search = collection_id;
|
let collection_id_for_search = collection_id;
|
||||||
let collection_name = collection.name.clone();
|
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 collection_search_handle = tokio::spawn(async move {
|
||||||
let mut conn = match get_pg_pool().get().await {
|
let mut conn = match get_pg_pool().get().await {
|
||||||
|
@ -143,8 +143,6 @@ pub async fn create_collection_handler(
|
||||||
collection,
|
collection,
|
||||||
assets: None,
|
assets: None,
|
||||||
permission: AssetPermissionRole::Owner,
|
permission: AssetPermissionRole::Owner,
|
||||||
individual_permissions: None,
|
|
||||||
team_permissions: None,
|
|
||||||
organization_permissions: false,
|
organization_permissions: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,15 +25,6 @@ pub async fn delete_collection_handler(
|
||||||
ids: Vec<Uuid>,
|
ids: Vec<Uuid>,
|
||||||
) -> Result<DeleteCollectionResponse> {
|
) -> 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
|
// Get database connection
|
||||||
let mut conn = match get_pg_pool().get().await {
|
let mut conn = match get_pg_pool().get().await {
|
||||||
Ok(conn) => conn,
|
Ok(conn) => conn,
|
||||||
|
@ -44,7 +35,7 @@ pub async fn delete_collection_handler(
|
||||||
|
|
||||||
// Soft delete the collections
|
// Soft delete the collections
|
||||||
match update(collections::table)
|
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())))
|
.set(collections::deleted_at.eq(Some(Utc::now())))
|
||||||
.execute(&mut conn)
|
.execute(&mut conn)
|
||||||
.await
|
.await
|
||||||
|
@ -57,6 +48,6 @@ pub async fn delete_collection_handler(
|
||||||
|
|
||||||
// Return the IDs of the deleted collections
|
// Return the IDs of the deleted collections
|
||||||
Ok(DeleteCollectionResponse {
|
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 uuid::Uuid;
|
||||||
|
|
||||||
use crate::collections::types::{CollectionState, GetCollectionRequest};
|
use crate::collections::types::{CollectionState, GetCollectionRequest};
|
||||||
|
@ -16,7 +17,15 @@ pub async fn get_collection_handler(
|
||||||
req: GetCollectionRequest,
|
req: GetCollectionRequest,
|
||||||
) -> Result<CollectionState> {
|
) -> Result<CollectionState> {
|
||||||
// Reuse the existing collection_utils function
|
// Reuse the existing collection_utils function
|
||||||
let collection = database::utils::collections::get_collection_by_id(user_id, &req.id).await?;
|
let collection = match fetch_collection(&req.id).await? {
|
||||||
|
Some(collection) => collection,
|
||||||
|
None => return Err(anyhow!("Collection not found")),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(collection)
|
Ok(CollectionState {
|
||||||
|
collection,
|
||||||
|
assets: None,
|
||||||
|
permission: AssetPermissionRole::Owner,
|
||||||
|
organization_permissions: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
// Collections handlers module
|
// Collections handlers module
|
||||||
// mod create_collection_handler;
|
mod create_collection_handler;
|
||||||
// mod delete_collection_handler;
|
mod delete_collection_handler;
|
||||||
// mod get_collection_handler;
|
mod get_collection_handler;
|
||||||
mod list_collections_handler;
|
mod list_collections_handler;
|
||||||
mod types;
|
mod types;
|
||||||
// mod update_collection_handler;
|
mod update_collection_handler;
|
||||||
|
|
||||||
// Re-export types
|
// Re-export types
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
// Re-export handlers
|
// Re-export handlers
|
||||||
// pub use create_collection_handler::create_collection_handler;
|
pub use create_collection_handler::create_collection_handler;
|
||||||
// pub use delete_collection_handler::delete_collection_handler;
|
pub use delete_collection_handler::delete_collection_handler;
|
||||||
// pub use get_collection_handler::get_collection_handler;
|
pub use get_collection_handler::get_collection_handler;
|
||||||
pub use list_collections_handler::list_collections_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,
|
pub type_: AssetType,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
// pub struct UpdateCollectionRequest {
|
pub struct UpdateCollectionRequest {
|
||||||
// pub id: Uuid,
|
pub id: Uuid,
|
||||||
// #[serde(flatten)]
|
pub collection: Option<UpdateCollectionObject>,
|
||||||
// pub collection: Option<UpdateCollectionObject>,
|
pub assets: Option<Vec<UpdateCollectionAssetsRequest>>,
|
||||||
// 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>>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Delete collection types
|
// Delete collection types
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use database::{
|
use database::{
|
||||||
enums::{AssetPermissionRole, AssetType},
|
collections::fetch_collection,
|
||||||
|
enums::AssetPermissionRole,
|
||||||
models::CollectionToAsset,
|
models::CollectionToAsset,
|
||||||
pool::get_pg_pool,
|
pool::get_pg_pool,
|
||||||
schema::{collections, collections_to_assets},
|
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 diesel_async::RunQueryDsl;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio;
|
use tokio;
|
||||||
|
@ -58,19 +59,6 @@ pub async fn update_collection_handler(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wait for all update operations to complete
|
// 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 {
|
if let Some(update_collection_record_handle) = update_collection_record_handle {
|
||||||
match update_collection_record_handle.await {
|
match update_collection_record_handle.await {
|
||||||
|
@ -101,14 +89,23 @@ pub async fn update_collection_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the updated collection
|
// Get the updated collection
|
||||||
let collection = database::utils::collections::get_collection_by_id(user_id.as_ref(), &req.id).await?;
|
let collection = match fetch_collection(&req.id).await? {
|
||||||
|
Some(collection) => collection,
|
||||||
|
None => return Err(anyhow!("Collection not found")),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(collection)
|
Ok(CollectionState {
|
||||||
|
collection,
|
||||||
|
assets: None,
|
||||||
|
permission: AssetPermissionRole::Owner,
|
||||||
|
organization_permissions: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update collection record in the database
|
/// Update collection record in the database
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
/// # Arguments
|
||||||
/// * `user_id` - The ID of the user updating the collection
|
/// * `user_id` - The ID of the user updating the collection
|
||||||
/// * `collection_id` - The ID of the collection to update
|
/// * `collection_id` - The ID of the collection to update
|
||||||
/// * `collection` - The collection update object
|
/// * `collection` - The collection update object
|
||||||
|
@ -176,7 +173,7 @@ async fn update_collection_record(
|
||||||
let query = diesel::sql_query(
|
let query = diesel::sql_query(
|
||||||
"UPDATE asset_search
|
"UPDATE asset_search
|
||||||
SET content = $1, updated_at = NOW()
|
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::Text, _>(collection_name)
|
||||||
.bind::<diesel::sql_types::Uuid, _>(*collection_id);
|
.bind::<diesel::sql_types::Uuid, _>(*collection_id);
|
||||||
|
|
|
@ -1,44 +1,30 @@
|
||||||
use axum::{
|
use axum::{extract::State, http::StatusCode, Extension, Json};
|
||||||
extract::State,
|
use handlers::collections::{create_collection_handler, CollectionState, CreateCollectionRequest};
|
||||||
http::StatusCode,
|
|
||||||
Json,
|
|
||||||
};
|
|
||||||
use handlers::collections::{create_collection_handler, CreateCollectionRequest, CollectionState};
|
|
||||||
use middleware::AuthenticatedUser;
|
use middleware::AuthenticatedUser;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use database::utils::user::get_user_organization_id;
|
|
||||||
|
|
||||||
/// Create a new collection
|
/// Create a new collection
|
||||||
///
|
///
|
||||||
/// This endpoint creates a new collection with the provided details.
|
/// This endpoint creates a new collection with the provided details.
|
||||||
pub async fn create_collection(
|
pub async fn create_collection(
|
||||||
user: AuthenticatedUser,
|
Extension(user): Extension<AuthenticatedUser>,
|
||||||
Json(req): Json<CreateCollectionRequest>,
|
Json(req): Json<CreateCollectionRequest>,
|
||||||
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
||||||
// Get the user's organization ID
|
// Get the user's organization ID
|
||||||
let org_id = match get_user_organization_id(&user.id).await {
|
let user_organization = match user.organizations.first() {
|
||||||
Ok(id) => id,
|
Some(org) => org,
|
||||||
Err(e) => {
|
None => return Err((StatusCode::NOT_FOUND, "User not found".to_string())),
|
||||||
tracing::error!("Error getting user organization ID: {}", e);
|
|
||||||
return Err((
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Error getting user organization: {}", e),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the handler
|
// 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)),
|
Ok(collection) => Ok(Json(collection)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Error creating collection: {}", e);
|
tracing::error!("Error creating collection: {}", e);
|
||||||
|
|
||||||
// Return appropriate error response based on the error
|
// Return appropriate error response based on the error
|
||||||
if e.to_string().contains("permission") {
|
if e.to_string().contains("permission") {
|
||||||
Err((
|
Err((StatusCode::FORBIDDEN, format!("Permission denied: {}", e)))
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
format!("Permission denied: {}", e),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err((
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
use axum::{
|
use axum::{http::StatusCode, Extension, Json};
|
||||||
http::StatusCode,
|
use handlers::collections::{
|
||||||
Json,
|
delete_collection_handler, DeleteCollectionRequest, DeleteCollectionResponse,
|
||||||
};
|
};
|
||||||
use handlers::collections::{delete_collection_handler, DeleteCollectionRequest, DeleteCollectionResponse};
|
|
||||||
use middleware::AuthenticatedUser;
|
use middleware::AuthenticatedUser;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use database::utils::user::get_user_organization_id;
|
|
||||||
|
|
||||||
/// Delete a collection
|
/// Delete a collection
|
||||||
///
|
///
|
||||||
|
@ -14,8 +12,13 @@ pub async fn delete_collection(
|
||||||
Extension(user): Extension<AuthenticatedUser>,
|
Extension(user): Extension<AuthenticatedUser>,
|
||||||
Json(req): Json<DeleteCollectionRequest>,
|
Json(req): Json<DeleteCollectionRequest>,
|
||||||
) -> Result<Json<DeleteCollectionResponse>, (StatusCode, String)> {
|
) -> 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
|
// 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)),
|
Ok(response) => Ok(Json(response)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Error deleting collection: {}", e);
|
tracing::error!("Error deleting collection: {}", e);
|
||||||
|
@ -27,10 +30,7 @@ pub async fn delete_collection(
|
||||||
format!("Collection not found: {}", e),
|
format!("Collection not found: {}", e),
|
||||||
))
|
))
|
||||||
} else if e.to_string().contains("permission") {
|
} else if e.to_string().contains("permission") {
|
||||||
Err((
|
Err((StatusCode::FORBIDDEN, format!("Permission denied: {}", e)))
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
format!("Permission denied: {}", e),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err((
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::Path,
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use handlers::collections::{get_collection_handler, CollectionState};
|
use handlers::collections::{get_collection_handler, CollectionState, GetCollectionRequest};
|
||||||
use middleware::AuthenticatedUser;
|
use middleware::AuthenticatedUser;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use axum::extract::Extension;
|
|
||||||
|
|
||||||
/// Get a collection by ID
|
/// Get a collection by ID
|
||||||
///
|
///
|
||||||
|
@ -15,8 +14,10 @@ pub async fn get_collection(
|
||||||
Extension(user): Extension<AuthenticatedUser>,
|
Extension(user): Extension<AuthenticatedUser>,
|
||||||
Path(id): Path<Uuid>,
|
Path(id): Path<Uuid>,
|
||||||
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
) -> Result<Json<CollectionState>, (StatusCode, String)> {
|
||||||
|
let request = GetCollectionRequest { id };
|
||||||
|
|
||||||
// Call the handler
|
// Call the handler
|
||||||
match get_collection_handler(&user.id, &id).await {
|
match get_collection_handler(&user.id, request).await {
|
||||||
Ok(collection) => Ok(Json(collection)),
|
Ok(collection) => Ok(Json(collection)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Error getting collection: {}", e);
|
tracing::error!("Error getting collection: {}", e);
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
routing::get,
|
routing::{get, post, put, delete},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod list_collections;
|
mod list_collections;
|
||||||
// mod get_collection;
|
mod get_collection;
|
||||||
// mod create_collection;
|
mod create_collection;
|
||||||
// mod update_collection;
|
mod update_collection;
|
||||||
// mod delete_collection;
|
mod delete_collection;
|
||||||
|
|
||||||
pub fn router() -> Router {
|
pub fn router() -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(list_collections::list_collections))
|
.route("/", get(list_collections::list_collections))
|
||||||
// .route("/", post(create_collection::create_collection))
|
.route("/", post(create_collection::create_collection))
|
||||||
// .route("/:id", get(get_collection::get_collection))
|
.route("/:id", get(get_collection::get_collection))
|
||||||
// .route("/:id", put(update_collection::update_collection))
|
.route("/:id", put(update_collection::update_collection))
|
||||||
// .route("/:id", delete(delete_collection::delete_collection))
|
.route("/:id", delete(delete_collection::delete_collection))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::{
|
use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use handlers::collections::{update_collection_handler, UpdateCollectionRequest, CollectionState};
|
use handlers::collections::{update_collection_handler, UpdateCollectionRequest, CollectionState};
|
||||||
use middleware::AuthenticatedUser;
|
use middleware::AuthenticatedUser;
|
||||||
|
|
Loading…
Reference in New Issue