Skip to content

Commit 26aec34

Browse files
committed
GCM/FCM device uuid
1 parent 129e599 commit 26aec34

File tree

4 files changed

+48
-29
lines changed

4 files changed

+48
-29
lines changed

push_notifications/api/rest_framework.py

+7-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import absolute_import
22

33
from rest_framework import permissions, status
4-
from rest_framework.fields import IntegerField
4+
from rest_framework.fields import UUIDField
55
from rest_framework.response import Response
66
from rest_framework.serializers import ModelSerializer, Serializer, ValidationError
77
from rest_framework.viewsets import ModelViewSet
@@ -11,25 +11,23 @@
1111
from ..settings import PUSH_NOTIFICATIONS_SETTINGS as SETTINGS
1212

1313

14-
# Fields
15-
class HexIntegerField(IntegerField):
14+
class UUIDIntegerField(UUIDField):
1615
"""
17-
Store an integer represented as a hex string of form "0x01".
16+
Store an integer represented as a UUID for backwards compatibiltiy. Also
17+
allows device_ids to be express as UUIDs.
1818
"""
1919

2020
def to_internal_value(self, data):
21-
# validate hex string and convert it to the unsigned
22-
# integer representation for internal use
2321
try:
22+
# maintain some semblence of backwards compatibility
2423
data = int(data, 16) if type(data) != int else data
2524
except ValueError:
2625
raise ValidationError("Device ID is not a valid hex number")
27-
return super(HexIntegerField, self).to_internal_value(data)
26+
return super(UUIDIntegerField, self).to_internal_value(data)
2827

2928
def to_representation(self, value):
3029
return value
3130

32-
3331
# Serializers
3432
class DeviceSerializerMixin(ModelSerializer):
3533
class Meta:
@@ -90,9 +88,8 @@ def validate(self, attrs):
9088

9189

9290
class GCMDeviceSerializer(UniqueRegistrationSerializerMixin, ModelSerializer):
93-
device_id = HexIntegerField(
91+
device_id = UUIDIntegerField(
9492
help_text="ANDROID_ID / TelephonyManager.getDeviceId() (e.g: 0x01)",
95-
style={"input_type": "text"},
9693
required=False,
9794
allow_null=True
9895
)
@@ -105,12 +102,6 @@ class Meta(DeviceSerializerMixin.Meta):
105102
)
106103
extra_kwargs = {"id": {"read_only": False, "required": False}}
107104

108-
def validate_device_id(self, value):
109-
# device ids are 64 bit unsigned values
110-
if value > UNSIGNED_64BIT_INT_MAX_VALUE:
111-
raise ValidationError("Device ID is out of range")
112-
return value
113-
114105

115106
class WNSDeviceSerializer(UniqueRegistrationSerializerMixin, ModelSerializer):
116107
class Meta(DeviceSerializerMixin.Meta):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.10.6 on 2017-04-08 19:17
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
import uuid
7+
8+
9+
def migrate_device_id(apps, schema_editor):
10+
GCMDevice = apps.get_model("push_notifications", "GCMDevice")
11+
for device in GCMDevice.objects.all():
12+
device.device_uuid = uuid.UUID(int=int(device.device_id, 16))
13+
device.save()
14+
15+
16+
class Migration(migrations.Migration):
17+
18+
dependencies = [
19+
('push_notifications', '0005_applicationid'),
20+
]
21+
22+
operations = [
23+
migrations.AddField(
24+
model_name='gcmdevice',
25+
name='device_uuid',
26+
field=models.UUIDField(blank=True, db_index=True, help_text='ANDROID_ID / TelephonyManager.getDeviceId()', null=True, verbose_name='Device ID'),
27+
),
28+
migrations.RunPython(migrate_device_id),
29+
migrations.RemoveField(
30+
model_name='gcmdevice',
31+
name='device_id',
32+
),
33+
migrations.RenameField(
34+
model_name='gcmdevice',
35+
old_name='device_uuid',
36+
new_name='device_id',
37+
),
38+
]

push_notifications/models.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from django.utils.encoding import python_2_unicode_compatible
44
from django.utils.translation import ugettext_lazy as _
55

6-
from .fields import HexIntegerField
76
from .settings import PUSH_NOTIFICATIONS_SETTINGS as SETTINGS
87

98

@@ -80,10 +79,11 @@ class GCMDevice(Device):
8079
# device_id cannot be a reliable primary key as fragmentation between different devices
8180
# can make it turn out to be null and such:
8281
# http://android-developers.blogspot.co.uk/2011/03/identifying-app-installations.html
83-
device_id = HexIntegerField(
82+
device_id = models.UUIDField(
8483
verbose_name=_("Device ID"), blank=True, null=True, db_index=True,
85-
help_text=_("ANDROID_ID / TelephonyManager.getDeviceId() (always as hex)")
84+
help_text=_("ANDROID_ID / TelephonyManager.getDeviceId()")
8685
)
86+
8787
registration_id = models.TextField(verbose_name=_("Registration ID"))
8888
cloud_message_type = models.CharField(
8989
verbose_name=_("Cloud Message Type"), max_length=3,

tests/test_rest_framework.py

-10
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,6 @@ def test_device_id_validation_fail_bad_hex(self):
108108
self.assertFalse(serializer.is_valid())
109109
self.assertEqual(serializer.errors, GCM_DRF_INVALID_HEX_ERROR)
110110

111-
def test_device_id_validation_fail_out_of_range(self):
112-
serializer = GCMDeviceSerializer(data={
113-
"registration_id": "foobar",
114-
"name": "Galaxy Note 3",
115-
"device_id": "10000000000000000", # 2**64
116-
"application_id": "XXXXXXXXXXXXXXXXXXXX",
117-
})
118-
self.assertFalse(serializer.is_valid())
119-
self.assertEqual(serializer.errors, GCM_DRF_OUT_OF_RANGE_ERROR)
120-
121111
def test_device_id_validation_value_between_signed_unsigned_64b_int_maximums(self):
122112
"""
123113
2**63 < 0xe87a4e72d634997c < 2**64

0 commit comments

Comments
 (0)