Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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.exception(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