Skip to content

Commit

Permalink
Update notification creation and sharing logic
Browse files Browse the repository at this point in the history
This commit updates the notification creation and sharing logic to include the `galaxy_url` field in the `NotificationCreateRequest` and `SharedItemNotificationFactory` classes. This field is used to generate links in the notification content and is passed as an argument when sending notifications to recipients.
  • Loading branch information
davelopez committed Apr 11, 2024
1 parent f402f40 commit 25013ea
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 13 deletions.
28 changes: 20 additions & 8 deletions lib/galaxy/managers/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Tuple,
Type,
)
from urllib.parse import urlparse

from pydantic import (
BaseModel,
Expand Down Expand Up @@ -52,14 +53,14 @@
from galaxy.schema.notifications import (
AnyNotificationContent,
BroadcastNotificationCreateRequest,
GenericNotificationCreate,
MandatoryNotificationCategory,
MessageNotificationContent,
NewSharedItemNotificationContent,
NotificationBroadcastUpdateRequest,
NotificationCategorySettings,
NotificationChannelSettings,
NotificationCreateData,
NotificationCreateRequest,
NotificationRecipients,
PersonalNotificationCategory,
UpdateUserNotificationPreferencesRequest,
Expand Down Expand Up @@ -154,7 +155,7 @@ def ensure_notifications_enabled(self):
def can_send_notifications_async(self):
return self.config.enable_celery_tasks

def send_notification_to_recipients(self, request: GenericNotificationCreate) -> Tuple[Optional[Notification], int]:
def send_notification_to_recipients(self, request: NotificationCreateRequest) -> Tuple[Optional[Notification], int]:
"""
Creates a new notification and associates it with all the recipient users.
Expand All @@ -163,7 +164,7 @@ def send_notification_to_recipients(self, request: GenericNotificationCreate) ->
"""
self.ensure_notifications_enabled()
recipient_users = self.recipient_resolver.resolve(request.recipients)
notification = self._create_notification_model(request.notification)
notification = self._create_notification_model(request.notification, request.galaxy_url)
self.sa_session.add(notification)
with transaction(self.sa_session):
self.sa_session.commit()
Expand Down Expand Up @@ -463,7 +464,9 @@ def cleanup_expired_notifications(self) -> CleanupResultSummary:

return CleanupResultSummary(deleted_notifications_count, deleted_associations_count)

def _create_notification_model(self, payload: NotificationCreateData):
def _create_notification_model(
self, payload: NotificationCreateData, galaxy_url: Optional[str] = None
) -> Notification:
notification = Notification(
payload.source,
payload.category,
Expand All @@ -472,6 +475,7 @@ def _create_notification_model(self, payload: NotificationCreateData):
)
notification.publication_time = payload.publication_time
notification.expiration_time = payload.expiration_time
notification.galaxy_url = galaxy_url
return notification

def _user_notifications_query(
Expand Down Expand Up @@ -650,6 +654,7 @@ class NotificationContext(BaseModel):
contact_email: str
notification_settings_url: str
content: AnyNotificationContent
galaxy_url: Optional[str] = None


class EmailNotificationTemplateBuilder(Protocol):
Expand Down Expand Up @@ -680,15 +685,22 @@ def build_context(self, template_format: TemplateFormats) -> NotificationContext
notification = self.notification
user = self.user
notification_date = notification.publication_time if notification.publication_time else notification.create_time
hostname = (
urlparse(self.notification.galaxy_url).hostname if self.notification.galaxy_url else self.config.server_name
)
notification_settings_url = (
f"{self.notification.galaxy_url}/user/notifications" if self.notification.galaxy_url else None
)
contact_email = self.config.error_email_to or None
return NotificationContext(
name=user.username,
user_email=user.email,
date=notification_date.strftime("%B %d, %Y"),
hostname=self.config.server_name,
contact_email=self.config.error_email_to or "",
# TODO: How to build the proper URL without access to trans?
notification_settings_url=f"https://{self.config.server_name}/user/notifications",
hostname=hostname,
contact_email=contact_email,
notification_settings_url=notification_settings_url,
content=self.get_content(template_format),
galaxy_url=self.notification.galaxy_url,
)

def get_body(self, template_format: TemplateFormats) -> str:
Expand Down
9 changes: 8 additions & 1 deletion lib/galaxy/schema/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,14 @@ class GenericNotificationCreate(GenericModel, Generic[DatabaseIdT]):
)


NotificationCreateRequest = GenericNotificationCreate[int]
class NotificationCreateRequest(GenericNotificationCreate[int]):
galaxy_url: Optional[str] = Field(
None,
title="Galaxy URL",
description="The URL of the Galaxy instance. Used to generate links in the notification content.",
)


NotificationRecipients = GenericNotificationRecipients[int]


Expand Down
4 changes: 4 additions & 0 deletions lib/galaxy/webapps/galaxy/services/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,13 @@ def send_notification(
"""
self.notification_manager.ensure_notifications_enabled()
self._ensure_user_can_send_notifications(sender_context)
galaxy_url = (
str(sender_context.url_builder("/", qualified=True)).rstrip("/") if sender_context.url_builder else None
)
request = NotificationCreateRequest.model_construct(
notification=payload.notification,
recipients=payload.recipients,
galaxy_url=galaxy_url,
)
return self.send_notification_internal(request)

Expand Down
14 changes: 10 additions & 4 deletions lib/galaxy/webapps/galaxy/services/sharable.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def share_with_users(self, trans, id: DecodedDatabaseIdField, payload: ShareWith
base_status = self._get_sharing_status(trans, item)
status = self.share_with_status_cls.model_construct(**base_status.model_dump(), extra=extra)
status.errors.extend(errors)
self._send_notification_to_users(users_to_notify, item, status)
galaxy_url = str(trans.url_builder("/", qualified=True)).rstrip("/") if trans.url_builder else None
self._send_notification_to_users(users_to_notify, item, status, galaxy_url)
return status

def _share_with_options(
Expand Down Expand Up @@ -173,13 +174,17 @@ def _get_users(self, trans, emails_or_ids: List[UserIdentifier]) -> Tuple[Set[Us

return send_to_users, send_to_err

def _send_notification_to_users(self, users_to_notify: Set[User], item: SharableItem, status: ShareWithStatus):
def _send_notification_to_users(
self, users_to_notify: Set[User], item: SharableItem, status: ShareWithStatus, galaxy_url: Optional[str] = None
):
if (
self.notification_service.notification_manager.notifications_enabled
and not status.errors
and users_to_notify
):
request = SharedItemNotificationFactory.build_notification_request(item, users_to_notify, status)
request = SharedItemNotificationFactory.build_notification_request(
item, users_to_notify, status, galaxy_url
)
# We can set force_sync=True here because we already have the set of users to notify
# and there is no need to resolve them asynchronously as no groups or roles are involved.
self.notification_service.send_notification_internal(request, force_sync=True)
Expand All @@ -197,7 +202,7 @@ class SharedItemNotificationFactory:

@staticmethod
def build_notification_request(
item: SharableItem, users_to_notify: Set[User], status: ShareWithStatus
item: SharableItem, users_to_notify: Set[User], status: ShareWithStatus, galaxy_url: Optional[str] = None
) -> NotificationCreateRequest:
user_ids = [user.id for user in users_to_notify]
request = NotificationCreateRequest(
Expand All @@ -213,5 +218,6 @@ def build_notification_request(
slug=status.username_and_slug,
),
),
galaxy_url=galaxy_url,
)
return request
1 change: 1 addition & 0 deletions test/unit/app/managers/test_NotificationManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def _send_message_notification_to_users(self, users: List[User], notification: O
user_ids=[user.id for user in users],
),
notification=notification_data,
galaxy_url="https://test.galaxy.url",
)
created_notification, notifications_sent = self.notification_manager.send_notification_to_recipients(request)
return created_notification, notifications_sent
Expand Down

0 comments on commit 25013ea

Please sign in to comment.