add user settings for info notifications (#1926)
# What this PR does ## Which issue(s) this PR fixes ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] 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)
This commit is contained in:
parent
ae5c4d368f
commit
c2ac74faa3
6 changed files with 100 additions and 6 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Add mobile settings for info notifications by @imtoori ([#1926](https://github.com/grafana/oncall/pull/1926))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix bug in the "You're Going Oncall" push notification copy by @joeyorlando ([#1922](https://github.com/grafana/oncall/pull/1922))
|
||||
|
|
|
|||
34
engine/apps/mobile_app/migrations/0006_auto_20230512_0902.py
Normal file
34
engine/apps/mobile_app/migrations/0006_auto_20230512_0902.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Generated by Django 3.2.19 on 2023-05-12 09:02
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mobile_app', '0005_mobileappusersettings_important_notification_volume_override'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mobileappusersettings',
|
||||
name='info_notification_sound_name',
|
||||
field=models.CharField(default='default_sound', max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mobileappusersettings',
|
||||
name='info_notification_volume',
|
||||
field=models.FloatField(default=0.8, null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1.0)]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mobileappusersettings',
|
||||
name='info_notification_volume_override',
|
||||
field=models.BooleanField(default=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mobileappusersettings',
|
||||
name='info_notification_volume_type',
|
||||
field=models.CharField(choices=[('constant', 'Constant'), ('intensifying', 'Intensifying')], default='constant', max_length=50, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -109,10 +109,23 @@ class MobileAppUserSettings(models.Model):
|
|||
# if "override DND" setting is disabled in the app
|
||||
important_notification_override_dnd = models.BooleanField(default=True)
|
||||
|
||||
# Push notification settings for info notifications
|
||||
# this is used for non escalation related push notifications such as the
|
||||
# "You're going OnCall soon" push notification
|
||||
info_notifications_enabled = models.BooleanField(default=True)
|
||||
|
||||
info_notification_sound_name = models.CharField(max_length=100, default="default_sound", null=True)
|
||||
info_notification_volume_type = models.CharField(
|
||||
max_length=50, choices=VolumeType.choices, default=VolumeType.CONSTANT, null=True
|
||||
)
|
||||
|
||||
# APNS only allows to specify volume for critical notifications,
|
||||
# so "info_notification_volume" and "info_notification_volume_override" are only used on Android
|
||||
info_notification_volume = models.FloatField(
|
||||
validators=[validators.MinValueValidator(0.0), validators.MaxValueValidator(1.0)], default=0.8, null=True
|
||||
)
|
||||
info_notification_volume_override = models.BooleanField(default=False, null=True)
|
||||
|
||||
# these choices + the below column are used to calculate when to send the "You're Going OnCall soon"
|
||||
# push notification
|
||||
# ONE_HOUR, TWELVE_HOURS, ONE_DAY, ONE_WEEK = range(4)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ class MobileAppUserSettingsSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = MobileAppUserSettings
|
||||
fields = (
|
||||
"info_notification_sound_name",
|
||||
"info_notification_volume_type",
|
||||
"info_notification_volume",
|
||||
"info_notification_volume_override",
|
||||
"default_notification_sound_name",
|
||||
"default_notification_volume_type",
|
||||
"default_notification_volume",
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ logger = get_task_logger(__name__)
|
|||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class MessageImportanceType(str, Enum):
|
||||
class MessageType(str, Enum):
|
||||
NORMAL = "oncall.message"
|
||||
CRITICAL = "oncall.critical_message"
|
||||
INFO = "oncall.info"
|
||||
|
||||
|
||||
class FCMMessageData(typing.TypedDict):
|
||||
|
|
@ -99,11 +100,11 @@ def _send_push_notification(
|
|||
|
||||
|
||||
def _construct_fcm_message(
|
||||
message_type: MessageType,
|
||||
device_to_notify: FCMDevice,
|
||||
thread_id: str,
|
||||
data: FCMMessageData,
|
||||
apns_payload: typing.Optional[APNSPayload] = None,
|
||||
critical_message_type: bool = False,
|
||||
) -> Message:
|
||||
apns_config_kwargs = {}
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ def _construct_fcm_message(
|
|||
# from the docs..
|
||||
# A dictionary of data fields (optional). All keys and values in the dictionary must be strings
|
||||
**data,
|
||||
"type": MessageImportanceType.CRITICAL if critical_message_type else MessageImportanceType.NORMAL,
|
||||
"type": message_type,
|
||||
"thread_id": thread_id,
|
||||
},
|
||||
android=AndroidConfig(
|
||||
|
|
@ -233,18 +234,48 @@ def _get_alert_group_escalation_fcm_message(
|
|||
),
|
||||
)
|
||||
|
||||
return _construct_fcm_message(device_to_notify, thread_id, fcm_message_data, apns_payload, critical)
|
||||
message_type = MessageType.CRITICAL if critical else MessageType.NORMAL
|
||||
|
||||
return _construct_fcm_message(message_type, device_to_notify, thread_id, fcm_message_data, apns_payload)
|
||||
|
||||
|
||||
def _get_youre_going_oncall_fcm_message(
|
||||
user: User, schedule: OnCallSchedule, device_to_notify: FCMDevice, seconds_until_going_oncall: int
|
||||
) -> Message:
|
||||
thread_id = f"{schedule.public_primary_key}:{user.public_primary_key}:going-oncall"
|
||||
|
||||
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}"
|
||||
)
|
||||
|
||||
data: FCMMessageData = {
|
||||
"title": f"You are going on call in {humanize.naturaldelta(seconds_until_going_oncall)} for schedule {schedule.name}",
|
||||
"title": notification_title,
|
||||
"info_notification_sound_name": (
|
||||
mobile_app_user_settings.info_notification_sound_name + MobileAppUserSettings.ANDROID_SOUND_NAME_EXTENSION
|
||||
),
|
||||
"info_notification_volume_type": mobile_app_user_settings.info_notification_volume_type,
|
||||
"info_notification_volume": str(mobile_app_user_settings.info_notification_volume),
|
||||
"info_notification_volume_override": json.dumps(mobile_app_user_settings.info_notification_volume_override),
|
||||
}
|
||||
|
||||
return _construct_fcm_message(device_to_notify, thread_id, data)
|
||||
apns_payload = APNSPayload(
|
||||
aps=Aps(
|
||||
thread_id=thread_id,
|
||||
alert=ApsAlert(title=notification_title),
|
||||
sound=CriticalSound(
|
||||
critical=False,
|
||||
name=mobile_app_user_settings.info_notification_sound_name
|
||||
+ MobileAppUserSettings.IOS_SOUND_NAME_EXTENSION,
|
||||
),
|
||||
custom_data={
|
||||
"interruption-level": "time-sensitive",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
return _construct_fcm_message(MessageType.INFO, device_to_notify, thread_id, data, apns_payload)
|
||||
|
||||
|
||||
@shared_dedicated_queue_retry_task(autoretry_for=(Exception,), retry_backoff=True, max_retries=MAX_RETRIES)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ def test_user_settings_get(make_organization_and_user_with_mobile_app_auth_token
|
|||
"default_notification_volume_type": "constant",
|
||||
"default_notification_volume": 0.8,
|
||||
"default_notification_volume_override": False,
|
||||
"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": "default_sound_important",
|
||||
"important_notification_volume_type": "constant",
|
||||
"important_notification_volume": 0.8,
|
||||
|
|
@ -52,6 +56,10 @@ def test_user_settings_put(
|
|||
"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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue