mirror of https://github.com/buster-so/buster.git
Merge branch 'staging' into big-nate/bus-891-reorganize-and-redo-permissions-tabs
This commit is contained in:
commit
b648951d6a
|
@ -1,25 +1,46 @@
|
|||
use anyhow::Result;
|
||||
use axum::{extract::Path, Extension, Json};
|
||||
use axum::http::StatusCode;
|
||||
use axum::{extract::Path, Extension};
|
||||
use diesel::prelude::*;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::database::enums::IdentityType;
|
||||
use crate::database::schema::sql_types::IdentityTypeEnum;
|
||||
use crate::database::schema::{datasets, permission_groups, permission_groups_to_identities};
|
||||
use crate::database::{
|
||||
enums::{UserOrganizationRole, UserOrganizationStatus},
|
||||
lib::get_pg_pool,
|
||||
models::User,
|
||||
schema::dataset_permissions,
|
||||
schema::{
|
||||
dataset_permissions, datasets_to_permission_groups, permission_groups_to_users, users,
|
||||
users_to_organizations,
|
||||
},
|
||||
};
|
||||
use crate::routes::rest::ApiResponse;
|
||||
use crate::utils::security::checks::is_user_workspace_admin_or_data_admin;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserPermissionLineage {
|
||||
pub id: Option<Uuid>,
|
||||
#[serde(rename = "type")]
|
||||
pub type_: String,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserOverviewItem {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub can_query: bool,
|
||||
pub lineage: Vec<Vec<UserPermissionLineage>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct DatasetOverview {
|
||||
pub dataset_id: Uuid,
|
||||
pub total_permission_groups: i64,
|
||||
pub total_dataset_groups: i64,
|
||||
pub total_users: i64,
|
||||
pub users: Vec<UserOverviewItem>,
|
||||
}
|
||||
|
||||
pub async fn get_dataset_overview(
|
||||
|
@ -32,7 +53,10 @@ pub async fn get_dataset_overview(
|
|||
Ok(false) => return Err((StatusCode::FORBIDDEN, "Insufficient permissions")),
|
||||
Err(e) => {
|
||||
tracing::error!("Error checking user permissions: {:?}", e);
|
||||
return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error checking user permissions"));
|
||||
return Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Error checking user permissions",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,58 +65,176 @@ pub async fn get_dataset_overview(
|
|||
(StatusCode::INTERNAL_SERVER_ERROR, "Database error")
|
||||
})?;
|
||||
|
||||
// Count active permissions for each type
|
||||
let permission_groups_count = dataset_permissions::table
|
||||
.filter(
|
||||
dataset_permissions::dataset_id
|
||||
.eq(dataset_id)
|
||||
.and(dataset_permissions::permission_type.eq("permission_group"))
|
||||
.and(dataset_permissions::deleted_at.is_null()),
|
||||
)
|
||||
.count()
|
||||
.get_result::<i64>(&mut *conn)
|
||||
// Get all active users in the organization
|
||||
let users = users_to_organizations::table
|
||||
.inner_join(users::table.on(users_to_organizations::user_id.eq(users::id)))
|
||||
.filter(users_to_organizations::status.eq(UserOrganizationStatus::Active))
|
||||
.filter(users_to_organizations::deleted_at.is_null())
|
||||
.select((users::id, users::email, users_to_organizations::role))
|
||||
.load::<(Uuid, String, UserOrganizationRole)>(&mut conn)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error counting permission groups: {:?}", e);
|
||||
tracing::error!("Error getting users: {:?}", e);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Database error")
|
||||
})?;
|
||||
|
||||
let dataset_groups_count = dataset_permissions::table
|
||||
.filter(
|
||||
dataset_permissions::dataset_id
|
||||
.eq(dataset_id)
|
||||
.and(dataset_permissions::permission_type.eq("dataset_group"))
|
||||
.and(dataset_permissions::deleted_at.is_null()),
|
||||
)
|
||||
.count()
|
||||
.get_result::<i64>(&mut *conn)
|
||||
let user_ids = users.iter().map(|(id, _, _)| *id).collect::<Vec<_>>();
|
||||
|
||||
let datasets_query: Vec<(Uuid, String, Uuid)> = dataset_permissions::table
|
||||
.inner_join(datasets::table.on(dataset_permissions::dataset_id.eq(datasets::id)))
|
||||
.filter(dataset_permissions::dataset_id.eq(dataset_id))
|
||||
.filter(dataset_permissions::permission_type.eq("user"))
|
||||
.filter(dataset_permissions::deleted_at.is_null())
|
||||
.filter(dataset_permissions::permission_id.eq_any(&user_ids))
|
||||
.select((
|
||||
datasets::id,
|
||||
datasets::name,
|
||||
dataset_permissions::permission_id,
|
||||
))
|
||||
.load::<(Uuid, String, Uuid)>(&mut conn)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error counting dataset groups: {:?}", e);
|
||||
tracing::error!("Error getting datasets: {:?}", e);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Database error")
|
||||
})?;
|
||||
|
||||
let users_count = dataset_permissions::table
|
||||
.filter(
|
||||
dataset_permissions::dataset_id
|
||||
.eq(dataset_id)
|
||||
.and(dataset_permissions::permission_type.eq("user"))
|
||||
.and(dataset_permissions::deleted_at.is_null()),
|
||||
let permission_groups_query: Vec<(Uuid, String, Uuid)> = permission_groups_to_identities::table
|
||||
.inner_join(
|
||||
permission_groups::table
|
||||
.on(permission_groups_to_identities::permission_group_id.eq(permission_groups::id)),
|
||||
)
|
||||
.count()
|
||||
.get_result::<i64>(&mut *conn)
|
||||
.inner_join(
|
||||
dataset_permissions::table.on(permission_groups_to_identities::permission_group_id
|
||||
.eq(dataset_permissions::permission_id)
|
||||
.and(dataset_permissions::permission_type.eq("permission_group"))),
|
||||
)
|
||||
.filter(permission_groups_to_identities::identity_id.eq_any(&user_ids))
|
||||
.filter(permission_groups_to_identities::identity_type.eq(IdentityType::User))
|
||||
.filter(dataset_permissions::deleted_at.is_null())
|
||||
.filter(dataset_permissions::dataset_id.eq(dataset_id))
|
||||
.filter(permission_groups::deleted_at.is_null())
|
||||
.select((
|
||||
permission_groups::id,
|
||||
permission_groups::name,
|
||||
permission_groups_to_identities::identity_id,
|
||||
))
|
||||
.load::<(Uuid, String, Uuid)>(&mut conn)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Error counting users: {:?}", e);
|
||||
tracing::error!("Error getting permission groups: {:?}", e);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, "Database error")
|
||||
})?;
|
||||
|
||||
let overview = DatasetOverview {
|
||||
dataset_id,
|
||||
total_permission_groups: permission_groups_count,
|
||||
total_dataset_groups: dataset_groups_count,
|
||||
total_users: users_count,
|
||||
};
|
||||
println!("datasets_query: {:?}", datasets_query);
|
||||
println!("permission_groups_query: {:?}", permission_groups_query);
|
||||
|
||||
// TODO: will need to add dataset groups here when we turn them on.
|
||||
|
||||
let users = users
|
||||
.into_iter()
|
||||
.map(|(id, email, role)| {
|
||||
let can_query = match role {
|
||||
UserOrganizationRole::WorkspaceAdmin => true,
|
||||
UserOrganizationRole::DataAdmin => true,
|
||||
UserOrganizationRole::Querier => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let mut lineage = vec![];
|
||||
let mut org_lineage = vec![UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Default Access")),
|
||||
}];
|
||||
|
||||
match role {
|
||||
UserOrganizationRole::WorkspaceAdmin => {
|
||||
org_lineage.push(UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Workspace Admin")),
|
||||
});
|
||||
}
|
||||
UserOrganizationRole::DataAdmin => {
|
||||
org_lineage.push(UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Data Admin")),
|
||||
});
|
||||
}
|
||||
UserOrganizationRole::Querier => {
|
||||
org_lineage.push(UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Querier")),
|
||||
});
|
||||
}
|
||||
UserOrganizationRole::RestrictedQuerier => {
|
||||
org_lineage.push(UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Restricted Querier")),
|
||||
});
|
||||
}
|
||||
UserOrganizationRole::Viewer => {
|
||||
org_lineage.push(UserPermissionLineage {
|
||||
id: Some(id),
|
||||
type_: String::from("user"),
|
||||
name: Some(String::from("Viewer")),
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
lineage.push(org_lineage);
|
||||
|
||||
// Add direct dataset access lineage
|
||||
if let Some((dataset_id, dataset_name, _)) =
|
||||
datasets_query.iter().find(|(_, _, user_id)| *user_id == id)
|
||||
{
|
||||
lineage.push(vec![
|
||||
UserPermissionLineage {
|
||||
id: None,
|
||||
type_: String::from("datasets"),
|
||||
name: Some(String::from("Datasets")),
|
||||
},
|
||||
UserPermissionLineage {
|
||||
id: Some(*dataset_id),
|
||||
type_: String::from("datasets"),
|
||||
name: Some(dataset_name.clone()),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
// Add permission group lineage
|
||||
if let Some((group_id, group_name, _)) = permission_groups_query
|
||||
.iter()
|
||||
.find(|(_, _, user_id)| *user_id == id)
|
||||
{
|
||||
lineage.push(vec![
|
||||
UserPermissionLineage {
|
||||
id: None,
|
||||
type_: String::from("permissionGroups"),
|
||||
name: Some(String::from("Permission Groups")),
|
||||
},
|
||||
UserPermissionLineage {
|
||||
id: Some(*group_id),
|
||||
type_: String::from("permissionGroups"),
|
||||
name: Some(group_name.clone()),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
return UserOverviewItem {
|
||||
id,
|
||||
name: email,
|
||||
can_query,
|
||||
lineage,
|
||||
};
|
||||
})
|
||||
.collect();
|
||||
|
||||
let overview = DatasetOverview { dataset_id, users };
|
||||
|
||||
Ok(ApiResponse::JsonData(overview))
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ pub struct AssetWithAssignment {
|
|||
pub assigned: bool,
|
||||
}
|
||||
|
||||
// TODO: When we introduce the dataset groups, this list should look for where they are included, not related to permissions.
|
||||
|
||||
pub async fn list_assets(
|
||||
Extension(user): Extension<User>,
|
||||
Path((dataset_id, permission_type)): Path<(Uuid, String)>,
|
||||
|
|
|
@ -23,6 +23,8 @@ pub struct AssetAssignment {
|
|||
pub assigned: bool,
|
||||
}
|
||||
|
||||
// TODO: When we introduce the dataset groups, this list should update the datasets_to_dataset_groups table, not related to permissions.
|
||||
|
||||
pub async fn put_permissions(
|
||||
Extension(user): Extension<User>,
|
||||
Path((dataset_id, permission_type)): Path<(Uuid, String)>,
|
||||
|
@ -78,7 +80,7 @@ pub async fn put_permissions_handler(
|
|||
.set(dataset_permissions::deleted_at.eq(Utc::now()))
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
|
||||
|
||||
tracing::debug!("Unassigned {} rows", rows_affected);
|
||||
}
|
||||
Ok::<_, anyhow::Error>(())
|
||||
|
|
Loading…
Reference in New Issue