Skip to content
This repository has been archived by the owner on Jan 28, 2019. It is now read-only.

Commit

Permalink
Merge pull request #31 from Fueled/zeropush_register_device
Browse files Browse the repository at this point in the history
feat(services/base): Added base method register_push_device()
  • Loading branch information
glemmaPaul committed Jun 9, 2015
2 parents c00899a + d4bf45a commit 171e191
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 42 deletions.
9 changes: 7 additions & 2 deletions push_notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ def remove_permissions(self, notice_types):

@classmethod
def register_push_device(cls, user, token, notice_types=None):
device, _ = cls.objects.get_or_create(token=token,
user=user)
registered = get_service().register_push_device(token)

if not registered:
return None

device, created = cls.objects.get_or_create(user=user, token=token)

if notice_types:
cls.change_permissions(notice_types, device)
return device
Expand Down
3 changes: 2 additions & 1 deletion push_notifications/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from django.core.exceptions import ImproperlyConfigured

# Local stuff
from .base import InvalidPushNotificationError
from .exceptions import InvalidPushNotificationError


SERVICE_NAME_KEY = 'SERVICE'

Expand Down
12 changes: 6 additions & 6 deletions push_notifications/services/base.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from django.core.exceptions import ImproperlyConfigured


class InvalidPushNotificationError(ImproperlyConfigured):
pass
# -*- coding: utf-8 -*-
from __future__ import absolute_import


class BaseService(object):

def __init__(self, configuration):
pass

def send_push_notification(devices, message,
def send_push_notification(self, devices, message,
badge_number=None, sound=None,
payload=None, expiry=None):
pass

def register_push_device(self, token):
return True
8 changes: 8 additions & 0 deletions push_notifications/services/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-

# Third party
from django.core.exceptions import ImproperlyConfigured


class InvalidPushNotificationError(ImproperlyConfigured):
pass
34 changes: 32 additions & 2 deletions push_notifications/services/zeropush.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

from .base import BaseService

ZEROPUSH_REQUEST_URL = 'https://api.zeropush.com/notify'
ZEROPUSH_REQUEST_URL = 'https://api.zeropush.com/'
ZEROPUSH_NOTIFY_URL = ZEROPUSH_REQUEST_URL + 'notify'
ZEROPUSH_REGISTER_URL = ZEROPUSH_REQUEST_URL + 'register'


class ZeroPushService(BaseService):
Expand All @@ -20,16 +22,28 @@ def __init__(self, settings):

@staticmethod
def process_expiry(expiry):
"""
Processes the expiry, checks if it's a datetime or timedelta and
responds accordingly
"""
if isinstance(expiry, datetime):
expiry = expiry.second

if isinstance(expiry, timedelta):
expiry = expiry.seconds
return expiry

def get_auth_headers(self):
return {
'Authorization': 'Token token="{}"'.format(self.auth_token)
}

def send_push_notification(self, devices, message,
badge_number=None, sound=None,
payload=None, expiry=None):
"""
Sends a push notification request to ZeroPush.
"""
if len(devices):
params = {
"auth_token": self.auth_token,
Expand All @@ -52,8 +66,24 @@ def send_push_notification(self, devices, message,
expiry = self.process_expiry(expiry)
params.update({'expiry': expiry})

response = requests.post(ZEROPUSH_REQUEST_URL, params)
response = requests.post(ZEROPUSH_NOTIFY_URL, params,
headers=self.get_auth_headers())

if response.ok:
return True
return False

def register_push_device(self, token):
"""
Registers a push device on zeropush.
"""
params = {
'device_token': token
}

response = requests.post(ZEROPUSH_REGISTER_URL, params,
headers=self.get_auth_headers())
if response.ok:
return True

return False
6 changes: 4 additions & 2 deletions push_notifications/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ def post(self, request, format=None):
serializer = DeviceTokenSerializer(data=request.data)
# check whether it's valid:
if serializer.is_valid():
PushDevice.register_push_device(
device = PushDevice.register_push_device(
request.user, serializer.validated_data['token'])
return Response({'registered': True})
registered = (True if device is not None else False)
status_code = (200 if registered is True else 400)
return Response({'registered': registered}, status=status_code)

return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
28 changes: 28 additions & 0 deletions tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Standard Library
import threading
import random
import json
import urlparse

# Third Party Stuff
import factory
Expand Down Expand Up @@ -51,3 +53,29 @@ class Meta:
name = factory.Sequence(lambda n: "Name {0}".format(n + 1))
device = factory.SubFactory('tests.factories.PushDeviceFactory')
send = random.choice([True, False])


# Make a mock of the response
def request_notify_callback(request):
payload = dict(urlparse.parse_qsl(request.body))
response_body = {
"sent_count": len(payload['device_tokens[]']),
"inactive_tokens": [],
"unregistered_tokens": []
}
headers = {
'Content-Type': 'application/json'
}
return (200, headers, json.dumps(response_body))


# Make a mock of the response of registering a device
def request_register_callback(request):
response_body = {
"message": "ok"
}
headers = {
'Content-Type': 'application/json'
}

return (200, headers, json.dumps(response_body))
34 changes: 33 additions & 1 deletion tests/test_register_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
from django.test import TestCase
from uuid import uuid4

# Third party
import responses

# Local stuff
from .factories import TestUserFactory
from .factories import TestUserFactory, request_register_callback
from push_notifications.services.zeropush import ZEROPUSH_REGISTER_URL
from push_notifications.models import PushDevice
from push_notifications.utils import register_push_device

Expand All @@ -17,21 +21,35 @@ def _create_token(self):
def _create_user(self):
return TestUserFactory.create()

@responses.activate
def test_register_device_manager(self):
"""
Test if register_device() on the manager works as expected
"""
responses.add_callback(
responses.POST, ZEROPUSH_REGISTER_URL,
callback=request_register_callback,
content_type='application/json',
)

user = TestUserFactory.create()
device = PushDevice.objects.register_push_device(
user, self._create_token())

assert device is not None
assert device.user.pk == user.pk

@responses.activate
def test_register_device_manager_notify_types(self):
"""
Test if manager.register_push_device() accepts notify_types
"""
responses.add_callback(
responses.POST, ZEROPUSH_REGISTER_URL,
callback=request_register_callback,
content_type='application/json',
)

user = self._create_user()
device = PushDevice.objects.register_push_device(
user, self._create_token(), notify_types='likes')
Expand All @@ -51,21 +69,35 @@ def test_register_device_manager_notify_types(self):
notification_comments = device.notification_settings.filter(name='comments').first()
assert notification_comments.send is True

@responses.activate
def test_register_device_service(self):
"""
Tests if register_push_device in services works as expected
"""
responses.add_callback(
responses.POST, ZEROPUSH_REGISTER_URL,
callback=request_register_callback,
content_type='application/json',
)

user = self._create_user()
device = register_push_device(user, self._create_token())

assert device is not None
assert device.user.pk == user.pk

@responses.activate
def test_register_device_service_notify_types(self):
"""
Tests if register_push_device in services workw with extra
notice_types
"""
responses.add_callback(
responses.POST, ZEROPUSH_REGISTER_URL,
callback=request_register_callback,
content_type='application/json',
)

user = self._create_user()
device = register_push_device(user, self._create_token(), notice_types='likes')

Expand Down
27 changes: 6 additions & 21 deletions tests/test_send_push_notification.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,27 @@
"""
Tests for send_push_notification methods
"""
import urlparse
import json
import random

from django.test import TestCase
from push_notifications.services.zeropush import ZEROPUSH_REQUEST_URL
from push_notifications.services.zeropush import ZEROPUSH_NOTIFY_URL
import responses

from push_notifications.utils import send_push_notification
from .factories import PushDeviceFactory, TestUserFactory
from .factories import (PushDeviceFactory, TestUserFactory,
request_notify_callback as request_callback)

from push_notifications.models import PushDevice


# Make a mock of the response
def request_callback(request):
payload = dict(urlparse.parse_qsl(request.body))
response_body = {
"sent_count": len(payload['device_tokens[]']),
"inactive_tokens": [],
"unregistered_tokens": []
}
headers = {
'Content-Type': 'application/json'
}
return (200, headers, json.dumps(response_body))


class SendPushNotificationTest(TestCase):
@responses.activate
def test_send_push_notification_utils(self):

devices = PushDeviceFactory.create_batch(random.randint(1, 10))

responses.add_callback(
responses.POST, ZEROPUSH_REQUEST_URL,
responses.POST, ZEROPUSH_NOTIFY_URL,
callback=request_callback,
content_type='application/json',
)
Expand All @@ -51,7 +36,7 @@ def test_send_push_notification_user(self):
PushDeviceFactory.create_batch(random.randint(1, 10), user=user)

responses.add_callback(
responses.POST, ZEROPUSH_REQUEST_URL,
responses.POST, ZEROPUSH_NOTIFY_URL,
callback=request_callback,
content_type='application/json',
)
Expand All @@ -66,7 +51,7 @@ def test_send_push_notification_objects_manager(self):
PushDeviceFactory.create_batch(random.randint(1, 10),
user=user)
responses.add_callback(
responses.POST, ZEROPUSH_REQUEST_URL,
responses.POST, ZEROPUSH_NOTIFY_URL,
callback=request_callback,
content_type='application/json',
)
Expand Down

0 comments on commit 171e191

Please sign in to comment.