-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add mobile app push notifications for shift swap requests #2717
Conversation
engine/apps/mobile_app/tasks.py
Outdated
@@ -230,13 +231,12 @@ def _get_youre_going_oncall_notification_title(seconds_until_going_oncall: int) | |||
return f"Your on-call shift starts in {humanize.naturaldelta(seconds_until_going_oncall)}" | |||
|
|||
|
|||
def _get_youre_going_oncall_notification_subtitle( | |||
def _get_shift_subtitle( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reusing this method to generate subtitles both for on-call shifts and SSRs
@@ -499,3 +499,183 @@ def conditionally_send_going_oncall_push_notifications_for_schedule(schedule_pk) | |||
def conditionally_send_going_oncall_push_notifications_for_all_schedules() -> None: | |||
for schedule in OnCallSchedule.objects.all(): | |||
conditionally_send_going_oncall_push_notifications_for_schedule.apply_async((schedule.pk,)) | |||
|
|||
|
|||
# TODO: break down tasks.py into multiple files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving this TODO out of the scope of this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed, good idea. Created #2722 to track this.
@@ -57,7 +57,7 @@ | |||
|
|||
|
|||
RE_ICAL_SEARCH_USERNAME = r"SUMMARY:(\[L[0-9]+\] )?{}" | |||
RE_ICAL_FETCH_USERNAME = re.compile(r"SUMMARY:(?:\[L[0-9]+\] )?(\w+)") | |||
RE_ICAL_FETCH_USERNAME = re.compile(r"SUMMARY:(?:\[L[0-9]+\] )?([^\s]+)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This didn't match usernames containing dots (e.g. vadim.stepanov
). Added a test for this case.
@@ -60,7 +60,7 @@ class ShiftSwapRequest(models.Model): | |||
default=generate_public_primary_key_for_shift_swap_request, | |||
) | |||
|
|||
created_at = models.DateTimeField(auto_now_add=True) | |||
created_at = models.DateTimeField(default=timezone.now) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is required to override created_at
in tests: FactoryBoy/factory_boy#102 (comment)
engine/apps/mobile_app/tasks.py
Outdated
from apps.mobile_app.models import MobileAppUserSettings | ||
|
||
thread_id = f"{shift_swap_request.public_primary_key}:{user.public_primary_key}:ssr" | ||
notification_title = "You have a new shift swap request" # TODO: decide on the exact wording |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me know if you have any ideas on notification title
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about "Your teammate has opened a shift swap request"? wdyt?
engine/apps/mobile_app/tasks.py
Outdated
# TODO: check with the mobile team | ||
resource_url = reverse("api-internal:shift_swap-detail", kwargs={"pk": shift_swap_request.public_primary_key}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to check this with @grafana/grafana-oncall-mobile, see here for the actual URL format
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #2717 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work, looks awesome!
@@ -480,6 +480,10 @@ class BrokerTypes: | |||
"task": "apps.mobile_app.tasks.conditionally_send_going_oncall_push_notifications_for_all_schedules", | |||
"schedule": 10 * 60, | |||
}, | |||
"notify_shift_swap_requests": { | |||
"task": "apps.mobile_app.tasks.notify_shift_swap_requests", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this also needs to be added to CELERY_TASK_ROUTES
(and also in oncall-private
), right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added in 747f3d7
@@ -283,6 +285,30 @@ def timezone(self) -> typing.Optional[str]: | |||
def timezone(self, value): | |||
self._timezone = value | |||
|
|||
def is_in_working_hours(self, dt: datetime.datetime, tz: typing.Optional[str] = None) -> bool: | |||
assert dt.tzinfo == pytz.utc # only pass in UTC |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -499,3 +499,183 @@ def conditionally_send_going_oncall_push_notifications_for_schedule(schedule_pk) | |||
def conditionally_send_going_oncall_push_notifications_for_all_schedules() -> None: | |||
for schedule in OnCallSchedule.objects.all(): | |||
conditionally_send_going_oncall_push_notifications_for_schedule.apply_async((schedule.pk,)) | |||
|
|||
|
|||
# TODO: break down tasks.py into multiple files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed, good idea. Created #2722 to track this.
for user in shift_swap_request.possible_benefactors: | ||
if _should_notify_user_about_shift_swap_request(shift_swap_request, user, now): | ||
notify_user_about_shift_swap_request.delay(shift_swap_request.pk, user.pk) | ||
_mark_shift_swap_request_notified_for_user(shift_swap_request, user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this happen at the very end of notify_user_about_shift_swap_request
? In case something inside there fails we probably don't want to mark the notification as sent. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't want to do that to make sure the mobile app doesn't spam people. I'd rather not receive any SSR notifications at all than receive more than one (potentially once every 15 minutes if something goes wrong between sending the push notification and marking the notification sent). The notify_user_about_shift_swap_request
task has a retry policy, so if something goes wrong while sending the push notification (e.g. network issue), the task will probably succeed after a retry. Lmk if this makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
task has a retry policy
ahh yes, forgot about this. Makes sense 👍
engine/apps/mobile_app/tasks.py
Outdated
from apps.mobile_app.models import MobileAppUserSettings | ||
|
||
thread_id = f"{shift_swap_request.public_primary_key}:{user.public_primary_key}:ssr" | ||
notification_title = "You have a new shift swap request" # TODO: decide on the exact wording |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about "Your teammate has opened a shift swap request"? wdyt?
engine/apps/mobile_app/tasks.py
Outdated
logger.info(f"Info notifications are not enabled for user {user_pk}") | ||
return | ||
|
||
if shift_swap_request.status != ShiftSwapRequest.Statuses.OPEN: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we could create a @property
on ShiftSwapRequest
as such:
@property
def is_open(self) -> bool:
return not any([self.is_deleted, self.is_taken, self.is_past_due])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, added in f747ec1
return ( | ||
mobile_app_user_settings.info_notifications_enabled # info notifications must be enabled | ||
and user.is_in_working_hours(now, mobile_app_user_settings.time_zone) # user must be in working hours | ||
and not _has_user_been_notified_for_shift_swap_request(shift_swap_request, user) # don't notify twice | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
What this PR does
Adds mobile app push notifications for shift swap requests.
Which issue(s) this PR fixes
#2630
Checklist
pr:no public docs
PR label added if not required)CHANGELOG.md
updated (orpr:no changelog
PR label added if not required)