mirror of https://github.com/buster-so/buster.git
ok filtering the chats and hiding shareWithChannel for now
This commit is contained in:
parent
0dd82ab1d1
commit
d7d4ab6401
|
@ -78,7 +78,7 @@ pub async fn list_chats_handler(
|
|||
request: ListChatsRequest,
|
||||
user: &AuthenticatedUser,
|
||||
) -> Result<Vec<ChatListItem>> {
|
||||
use database::schema::{asset_permissions, chats, messages, users};
|
||||
use database::schema::{asset_permissions, chats, messages, users, user_favorites};
|
||||
|
||||
let mut conn = get_pg_pool().get().await?;
|
||||
|
||||
|
@ -152,7 +152,29 @@ pub async fn list_chats_handler(
|
|||
// Get user's organization IDs
|
||||
let user_org_ids: Vec<Uuid> = user.organizations.iter().map(|org| org.id).collect();
|
||||
|
||||
// Get user's favorited chat IDs
|
||||
let favorited_chat_ids: Vec<Uuid> = if !request.admin_view {
|
||||
asset_permissions::table
|
||||
.filter(asset_permissions::identity_id.eq(user.id))
|
||||
.filter(asset_permissions::asset_type.eq(AssetType::Chat))
|
||||
.filter(asset_permissions::identity_type.eq(IdentityType::User))
|
||||
.filter(asset_permissions::deleted_at.is_null())
|
||||
.select(asset_permissions::asset_id)
|
||||
.union(
|
||||
user_favorites::table
|
||||
.filter(user_favorites::user_id.eq(user.id))
|
||||
.filter(user_favorites::asset_type.eq(AssetType::Chat))
|
||||
.filter(user_favorites::deleted_at.is_null())
|
||||
.select(user_favorites::asset_id)
|
||||
)
|
||||
.load::<Uuid>(&mut conn)
|
||||
.await?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// Second query: Get workspace-shared chats that the user doesn't have direct access to
|
||||
// but has either contributed to or favorited
|
||||
let workspace_shared_chats = if !request.admin_view && !user_org_ids.is_empty() {
|
||||
chats::table
|
||||
.inner_join(users::table.on(chats::created_by.eq(users::id)))
|
||||
|
@ -173,6 +195,24 @@ pub async fn list_chats_handler(
|
|||
))
|
||||
)
|
||||
)
|
||||
// Only include if user has contributed (created or updated a message) or favorited
|
||||
.filter(
|
||||
// User has favorited the chat
|
||||
chats::id.eq_any(&favorited_chat_ids)
|
||||
.or(
|
||||
// User has created a message in the chat
|
||||
diesel::dsl::exists(
|
||||
messages::table
|
||||
.filter(messages::chat_id.eq(chats::id))
|
||||
.filter(messages::created_by.eq(user.id))
|
||||
.filter(messages::deleted_at.is_null())
|
||||
)
|
||||
)
|
||||
.or(
|
||||
// User has updated the chat
|
||||
chats::updated_by.eq(user.id)
|
||||
)
|
||||
)
|
||||
.filter(
|
||||
diesel::dsl::exists(
|
||||
messages::table
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
use anyhow::Result;
|
||||
use database::{
|
||||
enums::{AssetType, WorkspaceSharing},
|
||||
models::{Chat, Message, UserFavorite},
|
||||
pool::get_pg_pool,
|
||||
schema::{chats, messages, user_favorites},
|
||||
tests::common::db::{TestDb, TestSetup},
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use handlers::chats::{list_chats_handler, ListChatsRequest};
|
||||
use middleware::UserOrganization;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_workspace_shared_chats_filtered_without_contribution() -> Result<()> {
|
||||
let setup = TestSetup::new(None).await?;
|
||||
let mut conn = setup.db.diesel_conn().await?;
|
||||
|
||||
// Create another user in the same organization
|
||||
let other_user = setup.db.create_user("other@example.com", "Other User").await?;
|
||||
|
||||
// Create a workspace-shared chat by the other user
|
||||
let shared_chat = Chat {
|
||||
id: Uuid::new_v4(),
|
||||
title: "Shared Chat".to_string(),
|
||||
organization_id: setup.organization.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
updated_by: other_user.id,
|
||||
publicly_accessible: false,
|
||||
publicly_enabled_by: None,
|
||||
public_expiry_date: None,
|
||||
most_recent_file_id: None,
|
||||
most_recent_file_type: None,
|
||||
most_recent_version_number: None,
|
||||
workspace_sharing: WorkspaceSharing::CanView,
|
||||
workspace_sharing_enabled_by: Some(other_user.id),
|
||||
workspace_sharing_enabled_at: Some(chrono::Utc::now()),
|
||||
};
|
||||
|
||||
diesel::insert_into(chats::table)
|
||||
.values(&shared_chat)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// Create a message in the chat by the other user
|
||||
let message = Message {
|
||||
id: Uuid::new_v4(),
|
||||
request_message: Some("Test message".to_string()),
|
||||
response_messages: serde_json::json!({}),
|
||||
reasoning: serde_json::json!({}),
|
||||
title: "Test".to_string(),
|
||||
raw_llm_messages: serde_json::json!({}),
|
||||
final_reasoning_message: None,
|
||||
chat_id: shared_chat.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
feedback: None,
|
||||
is_completed: true,
|
||||
post_processing_message: None,
|
||||
};
|
||||
|
||||
diesel::insert_into(messages::table)
|
||||
.values(&message)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// List chats for the test user - should NOT see the shared chat
|
||||
let request = ListChatsRequest {
|
||||
page: Some(1),
|
||||
page_size: 10,
|
||||
admin_view: false,
|
||||
};
|
||||
|
||||
let auth_user = middleware::AuthenticatedUser {
|
||||
id: setup.user.id,
|
||||
email: setup.user.email.clone(),
|
||||
name: setup.user.name.clone(),
|
||||
organizations: vec![UserOrganization {
|
||||
id: setup.organization.id,
|
||||
name: setup.organization.name.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = list_chats_handler(request, &auth_user).await?;
|
||||
|
||||
// Should not see the shared chat since user hasn't contributed
|
||||
assert_eq!(result.len(), 0);
|
||||
|
||||
// Clean up
|
||||
setup.db.cleanup().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_workspace_shared_chats_visible_with_contribution() -> Result<()> {
|
||||
let setup = TestSetup::new(None).await?;
|
||||
let mut conn = setup.db.diesel_conn().await?;
|
||||
|
||||
// Create another user in the same organization
|
||||
let other_user = setup.db.create_user("other@example.com", "Other User").await?;
|
||||
|
||||
// Create a workspace-shared chat by the other user
|
||||
let shared_chat = Chat {
|
||||
id: Uuid::new_v4(),
|
||||
title: "Shared Chat With Contribution".to_string(),
|
||||
organization_id: setup.organization.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
updated_by: other_user.id,
|
||||
publicly_accessible: false,
|
||||
publicly_enabled_by: None,
|
||||
public_expiry_date: None,
|
||||
most_recent_file_id: None,
|
||||
most_recent_file_type: None,
|
||||
most_recent_version_number: None,
|
||||
workspace_sharing: WorkspaceSharing::CanView,
|
||||
workspace_sharing_enabled_by: Some(other_user.id),
|
||||
workspace_sharing_enabled_at: Some(chrono::Utc::now()),
|
||||
};
|
||||
|
||||
diesel::insert_into(chats::table)
|
||||
.values(&shared_chat)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// Create a message by the other user
|
||||
let message1 = Message {
|
||||
id: Uuid::new_v4(),
|
||||
request_message: Some("Other user message".to_string()),
|
||||
response_messages: serde_json::json!({}),
|
||||
reasoning: serde_json::json!({}),
|
||||
title: "Test".to_string(),
|
||||
raw_llm_messages: serde_json::json!({}),
|
||||
final_reasoning_message: None,
|
||||
chat_id: shared_chat.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
feedback: None,
|
||||
is_completed: true,
|
||||
post_processing_message: None,
|
||||
};
|
||||
|
||||
diesel::insert_into(messages::table)
|
||||
.values(&message1)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// Create a message by the test user (contribution)
|
||||
let message2 = Message {
|
||||
id: Uuid::new_v4(),
|
||||
request_message: Some("Test user message".to_string()),
|
||||
response_messages: serde_json::json!({}),
|
||||
reasoning: serde_json::json!({}),
|
||||
title: "Test".to_string(),
|
||||
raw_llm_messages: serde_json::json!({}),
|
||||
final_reasoning_message: None,
|
||||
chat_id: shared_chat.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: setup.user.id, // Test user contributes
|
||||
feedback: None,
|
||||
is_completed: true,
|
||||
post_processing_message: None,
|
||||
};
|
||||
|
||||
diesel::insert_into(messages::table)
|
||||
.values(&message2)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// List chats for the test user - should see the shared chat
|
||||
let request = ListChatsRequest {
|
||||
page: Some(1),
|
||||
page_size: 10,
|
||||
admin_view: false,
|
||||
};
|
||||
|
||||
let auth_user = middleware::AuthenticatedUser {
|
||||
id: setup.user.id,
|
||||
email: setup.user.email.clone(),
|
||||
name: setup.user.name.clone(),
|
||||
organizations: vec![UserOrganization {
|
||||
id: setup.organization.id,
|
||||
name: setup.organization.name.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = list_chats_handler(request, &auth_user).await?;
|
||||
|
||||
// Should see the shared chat since user has contributed
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].name, "Shared Chat With Contribution");
|
||||
|
||||
// Clean up
|
||||
setup.db.cleanup().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_workspace_shared_chats_visible_when_favorited() -> Result<()> {
|
||||
let setup = TestSetup::new(None).await?;
|
||||
let mut conn = setup.db.diesel_conn().await?;
|
||||
|
||||
// Create another user in the same organization
|
||||
let other_user = setup.db.create_user("other@example.com", "Other User").await?;
|
||||
|
||||
// Create a workspace-shared chat by the other user
|
||||
let shared_chat = Chat {
|
||||
id: Uuid::new_v4(),
|
||||
title: "Favorited Shared Chat".to_string(),
|
||||
organization_id: setup.organization.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
updated_by: other_user.id,
|
||||
publicly_accessible: false,
|
||||
publicly_enabled_by: None,
|
||||
public_expiry_date: None,
|
||||
most_recent_file_id: None,
|
||||
most_recent_file_type: None,
|
||||
most_recent_version_number: None,
|
||||
workspace_sharing: WorkspaceSharing::CanView,
|
||||
workspace_sharing_enabled_by: Some(other_user.id),
|
||||
workspace_sharing_enabled_at: Some(chrono::Utc::now()),
|
||||
};
|
||||
|
||||
diesel::insert_into(chats::table)
|
||||
.values(&shared_chat)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// Create a message by the other user
|
||||
let message = Message {
|
||||
id: Uuid::new_v4(),
|
||||
request_message: Some("Other user message".to_string()),
|
||||
response_messages: serde_json::json!({}),
|
||||
reasoning: serde_json::json!({}),
|
||||
title: "Test".to_string(),
|
||||
raw_llm_messages: serde_json::json!({}),
|
||||
final_reasoning_message: None,
|
||||
chat_id: shared_chat.id,
|
||||
created_at: chrono::Utc::now(),
|
||||
updated_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
created_by: other_user.id,
|
||||
feedback: None,
|
||||
is_completed: true,
|
||||
post_processing_message: None,
|
||||
};
|
||||
|
||||
diesel::insert_into(messages::table)
|
||||
.values(&message)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// Add the chat to user's favorites
|
||||
let favorite = UserFavorite {
|
||||
user_id: setup.user.id,
|
||||
asset_id: shared_chat.id,
|
||||
asset_type: AssetType::Chat,
|
||||
order_index: 0,
|
||||
created_at: chrono::Utc::now(),
|
||||
deleted_at: None,
|
||||
};
|
||||
|
||||
diesel::insert_into(user_favorites::table)
|
||||
.values(&favorite)
|
||||
.execute(&mut conn)
|
||||
.await?;
|
||||
|
||||
// List chats for the test user - should see the shared chat
|
||||
let request = ListChatsRequest {
|
||||
page: Some(1),
|
||||
page_size: 10,
|
||||
admin_view: false,
|
||||
};
|
||||
|
||||
let auth_user = middleware::AuthenticatedUser {
|
||||
id: setup.user.id,
|
||||
email: setup.user.email.clone(),
|
||||
name: setup.user.name.clone(),
|
||||
organizations: vec![UserOrganization {
|
||||
id: setup.organization.id,
|
||||
name: setup.organization.name.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
let result = list_chats_handler(request, &auth_user).await?;
|
||||
|
||||
// Should see the shared chat since user has favorited it
|
||||
assert_eq!(result.len(), 1);
|
||||
assert_eq!(result[0].name, "Favorited Shared Chat");
|
||||
|
||||
// Clean up
|
||||
setup.db.cleanup().await?;
|
||||
Ok(())
|
||||
}
|
|
@ -33,3 +33,4 @@ pub mod sharing;
|
|||
pub mod metrics;
|
||||
pub mod dashboards;
|
||||
pub mod collections;
|
||||
pub mod chats_list_filter_test;
|
||||
|
|
|
@ -231,11 +231,11 @@ const SlackSharingPermissions = React.memo(() => {
|
|||
value: 'shareWithWorkspace',
|
||||
secondaryLabel: 'All workspace members will have access to any chat created from any channel.'
|
||||
},
|
||||
{
|
||||
label: 'Channel',
|
||||
value: 'shareWithChannel',
|
||||
secondaryLabel: 'All channel members will have access to any chat created from that channel.'
|
||||
},
|
||||
// {
|
||||
// label: 'Channel',
|
||||
// value: 'shareWithChannel',
|
||||
// secondaryLabel: 'All channel members will have access to any chat created from that channel.'
|
||||
// },
|
||||
{
|
||||
label: 'None',
|
||||
value: 'noSharing',
|
||||
|
|
Loading…
Reference in New Issue