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

Feature/boto3 #33

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion django_scarface/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.2.1-alpha'
__version__ = '4.0-alpha4'
6 changes: 3 additions & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
site_name: django-scarface
site_url: https://github.com/dreipol/django-scarface
site_author: dreipol GmbH
pages:
- [index.md, Getting Started]
theme: readthedocs
nav:
- 'Getting Started': index.md
theme: readthedocs
5 changes: 5 additions & 0 deletions readthedocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build:
image: latest

python:
version: 3.6
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pylint==1.4.0
pep8==1.5.7
django-apptemplates==0.0.1
boto==2.34.0
boto3==1.10.25
mkdocs==0.15.3
six==1.10.0
pytest
Expand Down
16 changes: 8 additions & 8 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Django==1.8
psycopg2>=2.5.4
pylint==1.4.0
pep8==1.5.7
django-apptemplates==0.0.1
boto==2.34.0
mkdocs==0.15.3
six==1.10.0
Django==1.11
psycopg2>=2.7.5
pylint==2.4.4
pep8==1.7.1
boto3==1.10.25
django-apptemplates==1.4
mkdocs==1.0.4
six==1.13.0
2 changes: 1 addition & 1 deletion scarface/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = '3.2.1'
__version__ = '4.0-alpha4'
default_app_config = 'scarface.apps.AppConfig'
76 changes: 37 additions & 39 deletions scarface/models.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import logging
from abc import abstractmethod, abstractproperty
import json
from boto.exception import BotoServerError
import logging
import re
from abc import abstractmethod

from django.db import models
from scarface.platform_strategy import get_strategies
from scarface.utils import DefaultConnection, PushLogger

from scarface.exceptions import SNSNotCreatedException, PlatformNotSupported, \
SNSException, NotRegisteredException

from scarface.platform_strategy import get_strategies
from scarface.utils import DefaultConnection, PushLogger

logger = logging.getLogger('django_scarface')


class SNSCRUDMixin(object):

@abstractproperty
@property
@abstractmethod
def resource_name(self):
pass

Expand Down Expand Up @@ -63,8 +64,7 @@ def set_arn_from_response(self, response_dict):
"""
success = False
try:
self.arn = response_dict[self.response_key][self.result_key][
self.arn_key]
self.arn = response_dict[self.arn_key]
success = True
except KeyError:
pass
Expand Down Expand Up @@ -182,9 +182,9 @@ def register(self, custom_user_data='', connection=None):
'''
self.platform.is_registered_or_register()
response = connection.create_platform_endpoint(
self.platform.arn,
self.push_token,
custom_user_data=custom_user_data
PlatformApplicationArn=self.platform.arn,
Token=self.push_token,
CustomUserData=custom_user_data
)
success = self.set_arn_from_response(response)
if not success:
Expand All @@ -208,9 +208,9 @@ def register_or_update(self, new_token=None, custom_user_data=u"",
try:
result = self.register(custom_user_data, connection)
# Heavily inspired by http://stackoverflow.com/a/28316993/270265
except BotoServerError as err:
except connection.exceptions.InvalidParameterException as err:
result_re = re.compile(r'Endpoint(.*)already', re.IGNORECASE)
result = result_re.search(err.message)
result = result_re.search(err.response['Error']['Message'])
if result:
arn = result.group(0).replace('Endpoint ', '').replace(
' already', '')
Expand All @@ -236,7 +236,7 @@ def deregister(self, connection=None, save=True):
"""
if not self.is_registered:
raise NotRegisteredException()
success = connection.delete_endpoint(self.arn)
success = connection.delete_endpoint(EndpointArn=self.arn)
if not success:
SNSException(
'Failed to deregister device.({0})'.format(success)
Expand All @@ -249,7 +249,7 @@ def deregister(self, connection=None, save=True):
def send_message(self, message, connection=None):
if not self.is_registered:
raise NotRegisteredException
return connection.publish(message=message, target_arn=self.arn)
return connection.publish(Message=message, TargetArn=self.arn)

@PushLogger
@DefaultConnection
Expand All @@ -265,9 +265,9 @@ def send(self, push_message, connection=None):
push_message = self.platform.format_payload(push_message)
json_string = json.dumps(push_message)
return connection.publish(
message=json_string,
target_arn=self.arn,
message_structure="json"
Message=json_string,
TargetArn=self.arn,
MessageStructure="json"
)

@DefaultConnection
Expand All @@ -282,10 +282,10 @@ def update(self, new_token=None, custom_user_data=u"", connection=None):
raise NotRegisteredException

new_token = new_token if new_token else self.push_token
attributes = {"Enabled": True, "Token": new_token}
attributes = {"Enabled": "true", "Token": new_token}
if custom_user_data:
attributes["CustomUserData"] = custom_user_data
answer = connection.set_endpoint_attributes(self.arn, attributes)
answer = connection.set_endpoint_attributes(EndpointArn=self.arn, Attributes=attributes)
self.is_enabled = True
self.push_token = new_token
return answer
Expand Down Expand Up @@ -371,9 +371,9 @@ def register(self, connection=None):
"""

response = connection.create_platform_application(
self.name,
self.platform,
self.attributes
Name=self.name,
Platform=self.platform,
Attributes=self.attributes
)
if not response:
raise SNSException(
Expand All @@ -392,7 +392,7 @@ def deregister(self, connection=None, save=True):
if not self.is_registered:
raise NotRegisteredException

success = connection.delete_platform_application(self.arn)
success = connection.delete_platform_application(PlatformApplicationArn=self.arn)
if not success:
SNSException(
'Failded to deregister Platform.({0})'.format(success)
Expand All @@ -413,9 +413,8 @@ def all_devices(self, connection=None):
endpoint_arns = list()

def get_next(nexttoken):
response = connection.list_endpoints_by_platform_application(
platform_application_arn=self.arn,
next_token=nexttoken)
response = connection.list_endpoints_by_platform_application(PlatformApplicationArn=self.arn,
NextToken=nexttoken)
result = response[u'ListEndpointsByPlatformApplicationResponse'][
u'ListEndpointsByPlatformApplicationResult']
endpoints = result[u'Endpoints']
Expand Down Expand Up @@ -472,7 +471,7 @@ def full_name(self):
@DefaultConnection
def register(self, connection=None):

response = connection.create_topic(self.full_name)
response = connection.create_topic(Name=self.full_name)
if not response:
raise SNSException(
'Failed to register Topic. ({0})'.format(response)
Expand All @@ -484,7 +483,7 @@ def register(self, connection=None):
def deregister(self, connection=None, save=True):
if not self.is_registered:
raise NotRegisteredException
success = connection.delete_topic(self.arn)
success = connection.delete_topic(TopicArn=self.arn)
if not success:
raise SNSException(
'Failed to deregister Topic. ({0})'.format(success)
Expand Down Expand Up @@ -536,8 +535,7 @@ def all_subscriptions(self, connection=None):
subscriptions_list = list()

def get_next(nexttoken):
response = connection.get_all_subscriptions_by_topic(
topic=self.arn, next_token=nexttoken)
response = connection.list_subscriptions_by_topic(TopicArn=self.arn, NextToken=nexttoken)
result = response["ListSubscriptionsByTopicResponse"][
"ListSubscriptionsByTopicResult"]
subs = result[u'Subscriptions']
Expand Down Expand Up @@ -572,9 +570,9 @@ def send(self, push_message, connection=None):
payload["default"] = push_message.message
json_string = json.dumps(payload)
return connection.publish(
message=json_string,
topic=self.arn,
message_structure="json"
Message=json_string,
TopicArn=self.arn,
MessageStructure="json"
)


Expand Down Expand Up @@ -642,9 +640,9 @@ def register(self, connection=None):
self.device.is_registered_or_register()
self.topic.is_registered_or_register()
success = connection.subscribe(
topic=self.topic.arn,
endpoint=self.device.arn,
protocol="application"
TopicArn=self.topic.arn,
Endpoint=self.device.arn,
Protocol="application"
)
if not success:
raise SNSException(
Expand All @@ -657,7 +655,7 @@ def register(self, connection=None):
def deregister(self, connection=None, save=True):
if not self.is_registered:
raise NotRegisteredException
success = connection.unsubscribe(self.arn)
success = connection.unsubscribe(SubscriptionArn=self.arn)
if not success:
raise SNSException(
'Failed to unsubscribe Device from Topic.({0})'.format(success)
Expand Down
8 changes: 4 additions & 4 deletions scarface/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import json
from unittest.mock import Mock

from boto.exception import BotoServerError
from botocore.exceptions import BotoCoreError
from django.test import TestCase
from scarface.exceptions import PlatformNotSupported
from scarface.platform_strategy import get_strategies, PlatformStrategy, APNPlatformStrategy
Expand Down Expand Up @@ -416,7 +416,7 @@ def test_update(self):
connection.set_endpoint_attributes.assert_called_once_with(
TEST_ARN_TOKEN_ANDROID_DEVICE,
{
'Enabled': True,
'Enabled': "true",
'Token': NEW_PUSH_TOKEN,
'CustomUserData': USER_DATA
}
Expand Down Expand Up @@ -542,7 +542,7 @@ def test_deregister_device(self):

try:
topic.deregister_device(device, connection)
except BotoServerError as e:
except BotoCoreError as e:
pass

connection.unsubscribe.assert_called_once_with(
Expand Down Expand Up @@ -632,4 +632,4 @@ def connection_test(a=None, connection=None):
# call_command("extract_keys", file="local_push.p12", password="bazinga",
# stdout=out)
# out_getvalue = out.getvalue()
# self.assertIn('SCARFACE_APNS_CERTIFICATE', out_getvalue)
# self.assertIn('SCARFACE_APNS_CERTIFICATE', out_getvalue)
17 changes: 8 additions & 9 deletions scarface/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import inspect
from functools import partial

from boto import sns
import boto3
from botocore.client import BaseClient
from django.conf import settings

__author__ = 'dreipol GmbH'
Expand Down Expand Up @@ -50,27 +51,25 @@ def __get__(self, obj, objtype=None):

def __call__(self, *args, **kwargs):
call_kwargs = inspect.getcallargs(self.original_function, *args,
**kwargs)
**kwargs)
push_message = call_kwargs.get('push_message')
self.obj.sign(push_message)
if logging_enabled():
push_message.save()
return self.function(*args, **kwargs)


def get_sns_connection():
def get_sns_connection() -> BaseClient:
"""
Creates a new AWS connection based upon the credentials defined in the django configuration
:param region: the region of the DynamoDB, defaults to Ireland
:return: a new dynamodb2 connection
"""

region = settings.SCARFACE_REGION_NAME if hasattr(settings, "SCARFACE_REGION_NAME") else 'eu-west-1'

return sns.connect_to_region(
region, aws_access_key_id=settings.AWS_ACCESS_KEY,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
)
sns = boto3.client('sns', aws_access_key_id=settings.AWS_ACCESS_KEY,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
region_name=region)
return sns


def logging_enabled():
Expand Down
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
else:
README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read()

reqs = ['boto>=2.34.0', ]
reqs = ['boto3>=1.10.0', ]

# allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
Expand All @@ -34,6 +34,7 @@ def get_version(*file_paths):
license='MIT License',
description='Send push notifications to mobile devices using Amazon SNS.',
long_description=README,
long_description_content_type='text/markdown',
url='http://www.dreipol.ch/',
author='dreipol GmbH',
author_email='[email protected]',
Expand All @@ -48,6 +49,7 @@ def get_version(*file_paths):
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Framework :: Django :: 1.11',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
Expand Down