Skip to content

Commit

Permalink
Merge branch 'release/3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
NachE committed May 25, 2023
2 parents 82a78f7 + fb53119 commit 86c96c6
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 56 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## [3.0]

## [3.0] - 2023-05-25

## Breaking Changes

Expand All @@ -11,6 +12,9 @@
- replace `pyAPNS2` with `aioapns` to enable Django>=4.0 compatibility and resolve unmaintained `hyper` dependency
- increase minimum Python version to 3.6

### Fixed

- sumer time switch bugfix

## [2.0] - 2023-01-09

Expand Down
67 changes: 34 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ This application implements the creation of **signed .pkpass** files and

## Requirements

- Django 2.*
- Python >= 3.5
- Django 2.*, 3.*, 4.*
- Python >= 3.6
- pyca/cryptography (for .pkpass SMIME sign)
- djangorestframework >= 3.8

Expand All @@ -36,10 +36,11 @@ $ pip install django-walletpass

Add 'django_walletpass' to you installed apps in the settings.py file.

Load the content of your cert.pem and key.pem in your settings.py file.
Load the content of your cert.pem and key.pem in your settings.py file. This is required
for signing the .pkpass file.

```

```python
WALLETPASS = {
'CERT_PATH': 'path/to/your/cert.pem',
'KEY_PATH': 'path/to/your/key.pem',
Expand All @@ -51,7 +52,7 @@ WALLETPASS = {

Add extra needed conf to your settings.py file.

```
```python
WALLETPASS = {
'CERT_PATH': 'path/to/your/cert.pem',
'KEY_PATH': 'path/to/your/key.pem',
Expand All @@ -65,9 +66,9 @@ WALLETPASS = {
}
```

If you plan to use token JWT auth instead key/cert, use:
Add token JWT config data to allow APNs push:

```
```python
WALLETPASS = {
'PUSH_AUTH_STRATEGY': 'token',
'TOKEN_AUTH_KEY_PATH': 'path/to/your/key.p8',
Expand All @@ -81,22 +82,22 @@ WALLETPASS = {


You should also import the urls into your site urls.
```
```python
urlpatterns = [
url(r'^api/passes/', include('django_walletpass.urls')),
```

django-walletpass signals certain events that might come handy in your
application.

```
from django_walletpass.views import pass_registered, pass_unregistered
```python
from django_walletpass.classviews import PASS_REGISTERED, PASS_UNREGISTERED

@receiver(pass_registered)
@receiver(PASS_REGISTERED)
def pass_registered(sender, **kwargs):
pass

@receiver(pass_unregistered)
@receiver(PASS_UNREGISTERED)
def pass_unregistered(sender, **kwargs):
pass
```
Expand All @@ -106,7 +107,7 @@ def pass_unregistered(sender, **kwargs):

Default: DEFAULT_FILE_STORAGE

```
```python
WALLETPASS_CONF = {
# Defaults to DEFAULT_FILE_STORAGE
'STORAGE_CLASS': 'my.custom.storageclass,
Expand All @@ -118,15 +119,15 @@ WALLETPASS_CONF = {

Default: False

```
```python
WALLETPASS_CONF = {
'PUSH_SANDBOX': False,
}
```

### CA certificates path (optional)

```
```python
WALLETPASS_CONF = {
# Cert in pem format.
'APPLE_WWDRCA_PEM_PATH': 'path/to/cert.pem',
Expand All @@ -139,7 +140,7 @@ files from `s3`.

Default: False

```
```python
WALLETPASS_CONF = {
STORAGE_HTTP_REDIRECT: True,
}
Expand All @@ -152,23 +153,23 @@ WALLETPASS_CONF = {

Init empty builder

```
from django_walletpass.models import PassBuilder
```python
from django_walletpass.models import PassBuilder
builder = PassBuilder()
```

Init builder usign a directory as base

```
from django_walletpass.models import PassBuilder
```python
from django_walletpass.models import PassBuilder
builder = PassBuilder(directory='/path/to/your.pass/')
```

If the base directory contains a `pass.json` it will be loaded, but remember
that required attributes of `pass.json` will be overwritten during build process
using this values:

```
```python
{
"passTypeIdentifier": WALLETPASS_CONF['PASS_TYPE_ID'],
"serialNumber": secrets.token_urlsafe(20),
Expand All @@ -186,7 +187,7 @@ can manage it like a normal python dictionary.

Update some attrs:

```
```python
builder.pass_data.update({
"barcode": {
"message": "123456789",
Expand All @@ -200,13 +201,13 @@ builder.pass_data.update({

Update one attr:

```
```python
builder.pass_data['description'] = "Organic Produce Loyalty Card"
```

### Overwrite automatically generated required attribute values

```
```python
builder.pass_data_required.update({
"passTypeIdentifier": "customvalue",
"serialNumber": "customvalue",
Expand All @@ -219,7 +220,7 @@ builder.pass_data_required.update({
you can overwrite individual attributes:


```
```python
builder.pass_data_required.update({
"serialNumber": "customvalue",
})
Expand All @@ -228,14 +229,14 @@ builder.pass_data_required['serialNumber] = 'cutomvalue'

### Add extra files

```
```python
file_content = open('myfile', 'rb').read()
builder.add_file('image.png', file_content)
```

You can also add files to directories:

```
```python
file_content = open('myfile', 'rb').read()
builder.add_file('en.lproj/pass.strings', file_content)
```
Expand All @@ -245,34 +246,34 @@ builder.add_file('en.lproj/pass.strings', file_content)

Build the content of .pkpass

```
```python
pkpass_content = builder.build()
```

Write to file:

```
```python
pkpass_file = open('mypass.pkpass', 'rb')
pkpass_file.write(pkpass_content)
```

Save to new record in DB:

```
```python
pass_instance = builder.write_to_model()
pass_instance.save()
```

Save to existent record in DB:

```
```python
builder.write_to_model(pass_instance)
pass_instance.save()
```

### Load .pkpass from DB and update

```
```python
builder = pass_instance.get_pass_builder()
builder.pass_data.update({'field': 'value'})
builder.build()
Expand All @@ -283,6 +284,6 @@ builder.save_to_db(pass_instance)

Checkout source and run from source root directory

```
```bash
docker run -it --rm -v "$(pwd):/app" python:3.8 bash -c "cd /app; python setup.py install; ./example/manage.py test django_walletpass"
```
28 changes: 15 additions & 13 deletions django_walletpass/classviews.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import json
from calendar import timegm

from pytz.exceptions import NonExistentTimeError

import django.dispatch
from dateutil.parser import parse
from django.db.models import Max
from django.http import HttpResponse
from django.utils.http import http_date
from django.middleware.http import ConditionalGetMiddleware
from django.db.models import Max
import django.dispatch
from django.shortcuts import get_object_or_404
from rest_framework import viewsets, status
from rest_framework.response import Response
from django.utils.http import http_date
from rest_framework import status, viewsets
from rest_framework.permissions import AllowAny
from django_walletpass.models import Pass, Registration, Log
from rest_framework.response import Response
from django_walletpass.models import Log, Pass, Registration
from django_walletpass.settings import dwpconfig as WALLETPASS_CONF
from pytz.exceptions import NonExistentTimeError
from dateutil.parser import parse

# legacy constant, remove when it can be assumed no timestamps of this format are out
# there anymore
Expand Down Expand Up @@ -43,11 +45,11 @@ def list(self, request, device_library_id, pass_type_id):
try:
# must be able to read UTC isoformat with TZ and FORMAT datetime string
# as well
dt = parse(request.GET['passesUpdatedSince'])
passes = passes.filter(updated_at__gt=dt)
date = parse(request.GET['passesUpdatedSince'])
passes = passes.filter(updated_at__gt=date)
except NonExistentTimeError:
dt = dt.replace(hour=0, minute=0)
passes = passes.filter(updated_at__gt=dt)
date = date.replace(hour=0, minute=0)
passes = passes.filter(updated_at__gt=date)

if passes:
last_updated = passes.aggregate(Max('updated_at'))['updated_at__max']
Expand Down Expand Up @@ -124,7 +126,7 @@ def retrieve(self, request, pass_type_id, serial_number):

response['Last-Modified'] = http_date(timegm(pass_.updated_at.utctimetuple()))

def _get_response(request):
def _get_response(_request):
return response

return ConditionalGetMiddleware(get_response=_get_response)(request)
Expand Down
2 changes: 1 addition & 1 deletion django_walletpass/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class Pass(models.Model):
updated_at = models.DateTimeField(auto_now=True)

def get_registrations(self):
return self.registrations.all()
return self.registrations.all()

def push_notification(self):
klass = import_string(WALLETPASS_CONF['WALLETPASS_PUSH_CLASS'])
Expand Down
2 changes: 1 addition & 1 deletion django_walletpass/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from ssl import SSLError

from aioapns import APNs, NotificationRequest
from aioapns.exceptions import ConnectionClosed, ConnectionError
from aioapns.exceptions import ConnectionClosed
from django_walletpass.models import Registration
from django_walletpass.settings import dwpconfig as WALLETPASS_CONF

Expand Down
13 changes: 7 additions & 6 deletions django_walletpass/tests/main.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
from unittest import mock

from dateutil.parser import parse
from django.test import TestCase
from django.utils import timezone
from django_walletpass import crypto
from django_walletpass.classviews import FORMAT
from django_walletpass.models import Pass, PassBuilder, Registration
from django_walletpass.settings import dwpconfig as WALLETPASS_CONF
from dateutil.parser import parse
from django.utils import timezone
from django_walletpass.classviews import FORMAT


class ClassViewsTestCase(TestCase):

def test_format_parse(self):
""" ensure dateutil reads FORMAT properly """
d = timezone.now()
s = d.strftime(FORMAT)
self.assertEqual(parse(s), timezone.make_naive(d).replace(microsecond=0))
now = timezone.now()
now_string = now.strftime(FORMAT)
self.assertEqual(parse(now_string), timezone.make_naive(now).replace(microsecond=0))


class CryptoTestCase(TestCase):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation :: CPython',
'Topic :: Software Development :: Internationalization',
'Topic :: Software Development :: Localization',
Expand Down

0 comments on commit 86c96c6

Please sign in to comment.