Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/adapter_processor_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class Meta(BaseAdapterSerializer.Meta):
"adapter_type",
"created_by",
"shared_users",
"shared_to_org",
) # type: ignore


Expand Down
47 changes: 45 additions & 2 deletions backend/adapter_processor_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,12 @@ def destroy(
def partial_update(
self, request: Request, *args: tuple[Any], **kwargs: dict[str, Any]
) -> Response:
# Store current shared users before update (for email notifications)
adapter = self.get_object()
current_shared_users = set(adapter.shared_users.all())

if AdapterKeys.SHARED_USERS in request.data:
# find the deleted users
adapter = self.get_object()
shared_users = {
int(user_id) for user_id in request.data.get("shared_users", {})
}
Expand Down Expand Up @@ -333,7 +336,47 @@ def partial_update(
)
continue

return super().partial_update(request, *args, **kwargs)
# Perform the update
response = super().partial_update(request, *args, **kwargs)

# Send email notifications to newly shared users
if response.status_code == 200 and AdapterKeys.SHARED_USERS in request.data:
try:
from plugins.notification.constants import ResourceType
from plugins.notification.sharing_notification import (
SharingNotificationService,
)

adapter.refresh_from_db()
new_shared_users = set(adapter.shared_users.all())
newly_shared_users = new_shared_users - current_shared_users

if newly_shared_users:
# Map adapter type to specific resource type
adapter_type_to_resource = {
"LLM": ResourceType.LLM.value,
"EMBEDDING": ResourceType.EMBEDDING.value,
"VECTOR_DB": ResourceType.VECTOR_DB.value,
"X2TEXT": ResourceType.X2TEXT.value,
}

resource_type = adapter_type_to_resource.get(
adapter.adapter_type, ResourceType.LLM.value
)

notification_service = SharingNotificationService()
notification_service.send_sharing_notification(
resource_type=resource_type,
resource_name=adapter.adapter_name,
resource_id=str(adapter.id),
shared_by=request.user,
shared_to=list(newly_shared_users),
resource_instance=adapter,
)
except Exception as e:
logger.error(f"Failed to send sharing notification: {e}")

return response

@action(detail=True, methods=["get"])
def list_of_shared_users(self, request: HttpRequest, pk: Any = None) -> Response:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,21 +170,28 @@ function ToolSettings({ type }) {
});
};

const onShare = (userIds, adapter) => {
const onShare = (userIds, adapter, shareWithEveryone) => {
const requestOptions = {
method: "PATCH",
url: `/api/v1/unstract/${sessionDetails?.orgId}/adapter/${adapter?.id}/`,
headers: {
"X-CSRFToken": sessionDetails?.csrfToken,
},
data: { shared_users: userIds },
data: {
shared_users: userIds,
shared_to_org: shareWithEveryone || false,
},
};
axiosPrivate(requestOptions)
.then((response) => {
setOpenSharePermissionModal(false);
setAlertDetails({
type: "success",
content: "Sharing settings updated successfully",
});
})
.catch((err) => {
setAlertDetails(handleException(err, "Failed to load"));
setAlertDetails(handleException(err, "Failed to update sharing"));
});
};

Expand Down Expand Up @@ -255,6 +262,7 @@ function ToolSettings({ type }) {
loading={isShareLoading}
allUsers={userList}
onApply={onShare}
isSharableToOrg={true}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ function SharePermission({
checked={shareWithEveryone}
onChange={(e) => handleShareWithEveryone(e.target.checked)}
className="share-per-checkbox"
disabled={!permissionEdit}
>
Share with everyone in current org
</Checkbox>
Expand Down