oncall-engine/engine/apps/mobile_app/serializers.py
Yulya Artyukhina 088414c4d3
Add multi-stack support for mobile app (#3500)
# What this PR does
Allow creating multiple mobile devices with same `registration_id` for
different users (multi-stack support)

## Which issue(s) this PR fixes
https://github.com/grafana/oncall/issues/3452

## 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)
2023-12-13 09:00:18 +00:00

82 lines
3.4 KiB
Python

import typing
from fcm_django.api.rest_framework import FCMDeviceSerializer as BaseFCMDeviceSerializer
from rest_framework import serializers
from rest_framework.serializers import ValidationError
from apps.mobile_app.models import MobileAppUserSettings
from common.api_helpers.custom_fields import TimeZoneField
class MobileAppUserSettingsSerializer(serializers.ModelSerializer):
time_zone = TimeZoneField(required=False, allow_null=False)
going_oncall_notification_timing = serializers.ListField(required=False, allow_null=False)
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",
"default_notification_volume_override",
"important_notification_sound_name",
"important_notification_volume_type",
"important_notification_volume",
"important_notification_volume_override",
"important_notification_override_dnd",
"info_notifications_enabled",
"going_oncall_notification_timing",
"locale",
"time_zone",
)
def validate_going_oncall_notification_timing(
self, going_oncall_notification_timing: typing.Optional[typing.List[int]]
) -> typing.Optional[typing.List[int]]:
if going_oncall_notification_timing is not None:
if len(going_oncall_notification_timing) == 0:
raise serializers.ValidationError(detail="invalid timing options")
notification_timing_options = [opt[0] for opt in MobileAppUserSettings.NOTIFICATION_TIMING_CHOICES]
for option in going_oncall_notification_timing:
if option not in notification_timing_options:
raise serializers.ValidationError(detail="invalid timing options")
return going_oncall_notification_timing
class FCMDeviceSerializer(BaseFCMDeviceSerializer):
def validate(self, attrs):
"""
Overrides `validate` method from BaseFCMDeviceSerializer to allow different users have same device
`registration_id` (multi-stack support).
Removed deactivating devices with the same `registration_id` during validation.
"""
devices = None
request_method = None
request = self.context["request"]
if self.initial_data.get("registration_id", None):
request_method = "update" if self.instance else "create"
else:
if request.method in ["PUT", "PATCH"]:
request_method = "update"
elif request.method == "POST":
request_method = "create"
Device = self.Meta.model
# unique together with registration_id and user
user = request.user
registration_id = attrs.get("registration_id")
if request_method == "update":
if registration_id:
devices = Device.objects.filter(registration_id=registration_id, user=user).exclude(id=self.instance.id)
elif request_method == "create":
devices = Device.objects.filter(user=user, registration_id=registration_id)
if devices:
raise ValidationError({"registration_id": "This field must be unique per us."})
return attrs