Skip to content

Commit

Permalink
[improvement] Add Swapper openwisp#86
Browse files Browse the repository at this point in the history
  • Loading branch information
atb00ker committed Apr 5, 2020
1 parent 056b7b9 commit 437a82a
Show file tree
Hide file tree
Showing 30 changed files with 466 additions and 272 deletions.
18 changes: 17 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ addons:
env:
- DJANGO="django>=2.2,<3.0"
- DJANGO="django>=3.0,<3.1"
- SAMPLE_APP=1 DJANGO="django>=2.2,<3.0"
- SAMPLE_APP=1 DJANGO="django>=3.0,<3.1"

branches:
only:
Expand All @@ -32,7 +34,21 @@ install:
- python setup.py -q develop

before_script:
- openwisp-utils-qa-checks --migrations-to-ignore 4 --migration-path ./django_x509/migrations/ --migration-module django_x509
- |
if [[ $SAMPLE_APP != "1" ]]; then
openwisp-utils-qa-checks --migrations-to-ignore 4 \
--migration-path ./django_x509/migrations/ \
--migration-module django_x509
else
openwisp-utils-qa-checks --skip-isort \
--skip-flake8 \
--skip-checkmigrations \
--skip-checkendline \
--skip-checkcommit \
--migration-path ./tests/sample_x509/migrations/ \
--migration-module sample_x509
fi
script:
- jslint django_x509/static/django-x509/js/*.js
Expand Down
16 changes: 16 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ be protected with authentication or not.
Extending django-x509
---------------------

The django app ``tests/openwisp2/sample_x509/`` adds some changes on
top of the ``django-x509`` module with the sole purpose of testing the
module's extensibility. It can be used as a sample for extending
``django-x509`` functionality in your own application.

*django-x509* provides a set of models and admin classes which can be imported,
extended and reused by third party apps.

Expand Down Expand Up @@ -394,6 +399,17 @@ Add ``openwisp_utils.loaders.DependencyLoader`` to ``TEMPLATES`` in your ``setti
}
]
5. Add swapper configurations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Add the following to your ``settings.py``:

.. code-block:: python
# Setting models for swapper module
DJANGO_X509_CA_MODEL = 'YOUR_MODULE_NAME.Ca'
DJANGO_X509_CERT_MODEL = 'YOUR_MODULE_NAME.Cert'
Extending models
~~~~~~~~~~~~~~~~

Expand Down
5 changes: 4 additions & 1 deletion django_x509/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from django.contrib import admin
from swapper import load_model

from .base.admin import AbstractCaAdmin, AbstractCertAdmin
from .models import Ca, Cert

Ca = load_model("django_x509", "Ca")
Cert = load_model("django_x509", "Cert")


class CertAdmin(AbstractCertAdmin):
Expand Down
5 changes: 4 additions & 1 deletion django_x509/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from datetime import datetime, timedelta

import OpenSSL
import swapper
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
Expand Down Expand Up @@ -473,7 +474,9 @@ class AbstractCert(BaseX509):
"""
Abstract Cert model
"""
ca = models.ForeignKey('django_x509.Ca', on_delete=models.CASCADE, verbose_name=_('CA'))
ca = models.ForeignKey(swapper.get_model_name('django_x509', 'Ca'),
on_delete=models.CASCADE,
verbose_name=_('CA'))
revoked = models.BooleanField(_('revoked'),
default=False)
revoked_at = models.DateTimeField(_('revoked at'),
Expand Down
4 changes: 4 additions & 0 deletions django_x509/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import swapper

from .base.models import AbstractCa, AbstractCert


Expand All @@ -7,6 +9,7 @@ class Ca(AbstractCa):
"""
class Meta(AbstractCa.Meta):
abstract = False
swappable = swapper.swappable_setting('django_x509', 'Ca')


class Cert(AbstractCert):
Expand All @@ -15,3 +18,4 @@ class Cert(AbstractCert):
"""
class Meta(AbstractCert.Meta):
abstract = False
swappable = swapper.swappable_setting('django_x509', 'Cert')
45 changes: 0 additions & 45 deletions django_x509/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,45 +0,0 @@
"""
test utilities shared among test classes
these mixins are reused also in openwisp2
change with care.
"""


class TestX509Mixin(object):
def _create_ca(self, **kwargs):
options = dict(name='Test CA',
key_length='2048',
digest='sha256',
country_code='IT',
state='RM',
city='Rome',
organization_name='OpenWISP',
email='test@test.com',
common_name='openwisp.org',
extensions=[])
options.update(kwargs)
ca = self.ca_model(**options)
ca.full_clean()
ca.save()
return ca

def _create_cert(self, **kwargs):
options = dict(name='TestCert',
ca=None,
key_length='2048',
digest='sha256',
country_code='IT',
state='RM',
city='Rome',
organization_name='Test',
email='test@test.com',
common_name='openwisp.org',
extensions=[])
options.update(kwargs)
# auto create CA if not supplied
if not options.get('ca'):
options['ca'] = self._create_ca()
cert = self.cert_model(**options)
cert.full_clean()
cert.save()
return cert
56 changes: 56 additions & 0 deletions django_x509/tests/base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from django.contrib.messages.storage.fallback import FallbackStorage
from django.http import HttpRequest


class MessagingRequest(HttpRequest):
session = 'session'

def __init__(self):
super().__init__()
self._messages = FallbackStorage(self)

def get_messages(self):
return getattr(self._messages, '_queued_messages')

def get_message_strings(self):
return [str(m) for m in self.get_messages()]


class TestX509Mixin(object):
def _create_ca(self, **kwargs):
options = dict(name='Test CA',
key_length='2048',
digest='sha256',
country_code='IT',
state='RM',
city='Rome',
organization_name='OpenWISP',
email='test@test.com',
common_name='openwisp.org',
extensions=[])
options.update(kwargs)
ca = self.ca_model(**options)
ca.full_clean()
ca.save()
return ca

def _create_cert(self, **kwargs):
options = dict(name='TestCert',
ca=None,
key_length='2048',
digest='sha256',
country_code='IT',
state='RM',
city='Rome',
organization_name='Test',
email='test@test.com',
common_name='openwisp.org',
extensions=[])
options.update(kwargs)
# auto create CA if not supplied
if not options.get('ca'):
options['ca'] = self._create_ca()
cert = self.cert_model(**options)
cert.full_clean()
cert.save()
return cert
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from django.contrib.admin.sites import AdminSite
from django.test import TestCase

from ..admin import CaAdmin, CertAdmin
from ..models import Ca, Cert
from .test_helpers import MessagingRequest
from . import MessagingRequest


class MockSuperUser:
Expand Down Expand Up @@ -88,24 +85,24 @@ def has_perm(self, perm):
'modified']


class ModelAdminTests(TestCase):
class AbstractModelAdminTests(object):

def setUp(self):
self.ca = Ca.objects.create()
self.cert = Cert.objects.create(ca_id=self.ca.pk)
self.ca = self.ca_model.objects.create()
self.cert = self.cert_model.objects.create(ca_id=self.ca.pk)
self.cert.ca = self.ca
self.site = AdminSite()

def test_modeladmin_str_ca(self):
ma = CaAdmin(Ca, self.site)
self.assertEqual(str(ma), 'django_x509.CaAdmin')
ma = self.ca_admin(self.ca_model, self.site)
self.assertEqual(str(ma), f'{self.app_name}.CaAdmin')

def test_modeladmin_str_certr(self):
ma = CertAdmin(Cert, self.site)
self.assertEqual(str(ma), 'django_x509.CertAdmin')
ma = self.cert_admin(self.cert_model, self.site)
self.assertEqual(str(ma), f'{self.app_name}.CertAdmin')

def test_default_fields_ca(self):
ma = CaAdmin(Ca, self.site)
ma = self.ca_admin(self.ca_model, self.site)
self.assertEqual(list(ma.get_form(request).base_fields), ca_fields)
ca_fields.insert(len(ca_fields), 'created')
ca_fields.insert(len(ca_fields), 'modified')
Expand All @@ -119,7 +116,7 @@ def test_default_fields_ca(self):
ca_fields.insert(pass_index, 'passphrase')

def test_default_fields_cert(self):
ma = CertAdmin(Cert, self.site)
ma = self.cert_admin(self.cert_model, self.site)
self.assertEqual(list(ma.get_form(request).base_fields), cert_fields)
cert_fields.insert(4, 'revoked')
cert_fields.insert(5, 'revoked_at')
Expand All @@ -135,32 +132,32 @@ def test_default_fields_cert(self):
cert_fields.insert(pass_index, 'passphrase')

def test_default_fieldsets_ca(self):
ma = CaAdmin(Ca, self.site)
ma = self.ca_admin(self.ca_model, self.site)
self.assertEqual(ma.get_fieldsets(request), [(None, {'fields': ca_fields})])

def test_default_fieldsets_cert(self):
ma = CertAdmin(Cert, self.site)
ma = self.cert_admin(self.cert_model, self.site)
self.assertEqual(ma.get_fieldsets(request), [(None, {'fields': cert_fields})])

def test_readonly_fields_Ca(self):
ma = CaAdmin(Ca, self.site)
ma = self.ca_admin(self.ca_model, self.site)
self.assertEqual(ma.get_readonly_fields(request), ('created', 'modified'))
self.assertEqual(ma.get_readonly_fields(request, self.ca), tuple(ca_readonly))
ca_readonly.remove('created')
ca_readonly.remove('modified')

def test_readonly_fields_Cert(self):
ma = CertAdmin(Cert, self.site)
ma = self.cert_admin(self.cert_model, self.site)
self.assertEqual(ma.get_readonly_fields(request), cert_readonly)
ca_readonly.append('ca')
self.assertEqual(ma.get_readonly_fields(request, self.cert), tuple(ca_readonly + cert_readonly))

def test_ca_url(self):
ma = CertAdmin(Cert, self.site)
self.assertEqual(ma.ca_url(self.cert), "<a href='/admin/django_x509/ca/1/change/'></a>")
ma = self.cert_admin(self.cert_model, self.site)
self.assertEqual(ma.ca_url(self.cert), f"<a href='/admin/{self.app_name}/ca/1/change/'></a>")

def test_revoke_action(self):
ma = CertAdmin(Cert, self.site)
ma = self.cert_admin(self.cert_model, self.site)
ma.revoke_action(request, [self.cert])
m = list(request.get_messages())
self.assertEqual(len(m), 1)
Expand Down
Loading

0 comments on commit 437a82a

Please sign in to comment.