Skip to content

Commit

Permalink
add user locale field to mobile app user settings table + change goin…
Browse files Browse the repository at this point in the history
…g on call push notification text (#2131)

# What this PR does

- add user locale field to mobile app user settings table + add a test
that sends `PATCH` requests to this endpoint
- change "you're going on call" push notification text to include
localized shift time. The general format is now:
  ```python
f"You're going on call in {time_until_going_oncall} for schedule
{schedule.name}, {formatted_shift}"
  ```
- `time_until_going_oncall` is a "human-readable" format of the time
until the start)
  - `schedule.name` is self-explanatory
- `formatted_shift` this depends on the shift. If the shift starts and
ends on the same day, the format will be "HH:mm - HH:mm". Otherwise, if
the shift starts and ends on different days, the format will be
"YYYY-MM-DD HH:mm - YYYY-MM-DD HH:mm". **Note** that all datetime
related formatting will use the new `locale` field that we are now
storing in the mobile app user settings table. If no locale is yet
present we will fallback to "en"

## Which issue(s) this PR fixes

closes #2024
grafana/oncall-mobile-app#187

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
  • Loading branch information
joeyorlando authored Jun 14, 2023
1 parent c8669ce commit 572131b
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 19 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Add `locale` column to mobile app user settings table by @joeyorlando [#2131](https://github.com/grafana/oncall/pull/2131)
- Update notification text for "You're going on call" push notifications to include information about the shift start
and end times by @joeyorlando ([#2131](https://github.com/grafana/oncall/pull/2131))

## v1.2.44 (2023-06-14)

### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.19 on 2023-06-08 10:51

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mobile_app', '0007_alter_mobileappusersettings_info_notifications_enabled'),
]

operations = [
migrations.AddField(
model_name='mobileappusersettings',
name='locale',
field=models.CharField(max_length=50, null=True),
),
]
2 changes: 2 additions & 0 deletions engine/apps/mobile_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,5 @@ class VolumeType(models.TextChoices):
going_oncall_notification_timing = models.IntegerField(
choices=NOTIFICATION_TIMING_CHOICES, default=TWELVE_HOURS_IN_SECONDS
)

locale = models.CharField(max_length=50, null=True)
1 change: 1 addition & 0 deletions engine/apps/mobile_app/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ class Meta:
"important_notification_override_dnd",
"info_notifications_enabled",
"going_oncall_notification_timing",
"locale",
)
34 changes: 30 additions & 4 deletions engine/apps/mobile_app/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from apps.user_management.models import User
from common.api_helpers.utils import create_engine_url
from common.custom_celery_tasks import shared_dedicated_queue_retry_task
from common.l10n import format_localized_datetime, format_localized_time

if typing.TYPE_CHECKING:
from apps.mobile_app.models import MobileAppUserSettings
Expand Down Expand Up @@ -225,8 +226,33 @@ def _get_alert_group_escalation_fcm_message(
return _construct_fcm_message(message_type, device_to_notify, thread_id, fcm_message_data, apns_payload)


def _get_youre_going_oncall_notification_title(
schedule: OnCallSchedule,
seconds_until_going_oncall: int,
schedule_event: ScheduleEvent,
mobile_app_user_settings: "MobileAppUserSettings",
) -> str:
time_until_going_oncall = humanize.naturaldelta(seconds_until_going_oncall)

shift_start = schedule_event["start"]
shift_end = schedule_event["end"]
shift_starts_and_ends_on_same_day = shift_start.date() == shift_end.date()
dt_formatter_func = format_localized_time if shift_starts_and_ends_on_same_day else format_localized_datetime

def _format_datetime(dt):
return dt_formatter_func(dt, mobile_app_user_settings.locale)

formatted_shift = f"{_format_datetime(shift_start)} - {_format_datetime(shift_end)}"

return f"You're going on call in {time_until_going_oncall} for schedule {schedule.name}, {formatted_shift}"


def _get_youre_going_oncall_fcm_message(
user: User, schedule: OnCallSchedule, device_to_notify: FCMDevice, seconds_until_going_oncall: int
user: User,
schedule: OnCallSchedule,
device_to_notify: FCMDevice,
seconds_until_going_oncall: int,
schedule_event: ScheduleEvent,
) -> Message:
# avoid circular import
from apps.mobile_app.models import MobileAppUserSettings
Expand All @@ -235,8 +261,8 @@ def _get_youre_going_oncall_fcm_message(

mobile_app_user_settings, _ = MobileAppUserSettings.objects.get_or_create(user=user)

notification_title = (
f"You are going on call in {humanize.naturaldelta(seconds_until_going_oncall)} for schedule {schedule.name}"
notification_title = _get_youre_going_oncall_notification_title(
schedule, seconds_until_going_oncall, schedule_event, mobile_app_user_settings
)

data: FCMMessageData = {
Expand Down Expand Up @@ -446,7 +472,7 @@ def conditionally_send_going_oncall_push_notifications_for_schedule(schedule_pk)

if seconds_until_going_oncall is not None and not already_sent_this_push_notification:
message = _get_youre_going_oncall_fcm_message(
user, schedule, device_to_notify, seconds_until_going_oncall
user, schedule, device_to_notify, seconds_until_going_oncall, schedule_event
)
_send_push_notification(device_to_notify, message)
cache.set(cache_key, True, PUSH_NOTIFICATION_TRACKING_CACHE_KEY_TTL)
Expand Down
41 changes: 41 additions & 0 deletions engine/apps/mobile_app/tests/test_user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def test_user_settings_get(make_organization_and_user_with_mobile_app_auth_token
"important_notification_override_dnd": True,
"info_notifications_enabled": False,
"going_oncall_notification_timing": 43200,
"locale": None,
}


Expand Down Expand Up @@ -67,6 +68,7 @@ def test_user_settings_put(
"important_notification_override_dnd": False,
"info_notifications_enabled": True,
"going_oncall_notification_timing": going_oncall_notification_timing,
"locale": "ca_FR",
}

response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=auth_token)
Expand All @@ -75,3 +77,42 @@ def test_user_settings_put(
if expected_status_code == status.HTTP_200_OK:
# Check the values are updated correctly
assert response.json() == data


@pytest.mark.django_db
def test_user_settings_patch(make_organization_and_user_with_mobile_app_auth_token):
_, _, auth_token = make_organization_and_user_with_mobile_app_auth_token()

original_default_notification_sound_name = "test_default"
patch_default_notification_sound_name = "test_default_patched"

client = APIClient()
url = reverse("mobile_app:user_settings")
data = {
"default_notification_sound_name": original_default_notification_sound_name,
"default_notification_volume_type": "intensifying",
"default_notification_volume": 1,
"default_notification_volume_override": True,
"info_notification_sound_name": "default_sound",
"info_notification_volume_type": "constant",
"info_notification_volume": 0.8,
"info_notification_volume_override": False,
"important_notification_sound_name": "test_important",
"important_notification_volume_type": "intensifying",
"important_notification_volume": 1,
"important_notification_volume_override": False,
"important_notification_override_dnd": False,
"info_notifications_enabled": True,
}

response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=auth_token)
original_settings = response.json()

assert response.status_code == status.HTTP_200_OK

patch_data = {"default_notification_sound_name": patch_default_notification_sound_name}
response = client.patch(url, data=patch_data, format="json", HTTP_AUTHORIZATION=auth_token)

assert response.status_code == status.HTTP_200_OK
# all original settings should stay the same, only data set in PATCH call should get updated
assert response.json() == {**original_settings, **patch_data}
Loading

0 comments on commit 572131b

Please sign in to comment.