diff --git a/.gitignore b/.gitignore
index 84bbba5..6c32372 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@
.vscode/
build/
+ve/
dist/
htmlcov/
docs/_build
diff --git a/.travis.yml b/.travis.yml
index 7d20c4a..69b1841 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,8 @@ matrix:
env: TOXENV=py36-django20-wagtail21
- python: 3.6
env: TOXENV=py36-django20-wagtail21-geoip2
+ - python: 3.6
+ env: TOXENV=py36-django111-wagtail22
install:
- pip install tox codecov
diff --git a/CHANGES b/CHANGES
index 11c81de..a9a971a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,10 +1,18 @@
+0.13.0
+=================
+ - Merged Praekolt fork
+ - Add custom javascript to segment forms
+ - bugfix:exclude variant returns queryset when params is queryset
+ - Added RulePanel, a subclass of InlinePanel, for Rules
+ - Upgrade to Wagtail > 2.0, drop support for Wagtail < 2
+
0.12.0
==================
- Fix Django version classifier in setup.py
0.12.0
==================
- - Merged forks of Torchbox and Praekelt
+ - Merged forks of Torchbox and Praekolt
- Wagtail 2 compatibility
- Makefile adjustments for portability
- Adds simple segment forcing for superusers
diff --git a/VERSON b/VERSON
new file mode 100644
index 0000000..21e8796
--- /dev/null
+++ b/VERSON
@@ -0,0 +1 @@
+1.0.3
diff --git a/docs/conf.py b/docs/conf.py
index b87f0a4..e4c566d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -54,7 +54,7 @@ master_doc = 'index'
# General information about the project.
project = 'wagtail-personalisation'
-copyright = '2018, Lab Digital BV'
+copyright = '2019, Lab Digital BV'
author = 'Lab Digital BV'
# The version info for the project you're documenting, acts as replacement for
diff --git a/setup.py b/setup.py
index e082272..1581033 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ import re
from setuptools import find_packages, setup
install_requires = [
- 'wagtail>=2.0',
+ 'wagtail>=2.0,<2.3',
'user-agents>=1.1.0',
'wagtailfontawesome>=1.1.3',
'pycountry',
@@ -20,7 +20,7 @@ tests_require = [
'pytest-pythonpath==0.7.2',
'pytest-sugar==0.9.1',
'pytest==3.4.2',
- 'wagtail_factories==1.0.0',
+ 'wagtail_factories==1.1.0',
'pytest-mock==1.6.3',
]
@@ -52,7 +52,7 @@ setup(
license='MIT',
long_description=long_description,
classifiers=[
- 'Development Status :: 2 - Pre-Alpha',
+ 'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
diff --git a/src/wagtail_personalisation/models.py b/src/wagtail_personalisation/models.py
index 124a0f1..1e167f4 100644
--- a/src/wagtail_personalisation/models.py
+++ b/src/wagtail_personalisation/models.py
@@ -1,16 +1,15 @@
import random
+import wagtail
from django import forms
from django.conf import settings
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models, transaction
from django.template.defaultfilters import slugify
-from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from modelcluster.models import ClusterableModel
-import wagtail
from wagtail.admin.edit_handlers import (
FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel)
from wagtail.core.models import Page
@@ -21,12 +20,19 @@ from wagtail_personalisation.utils import count_active_days
from .forms import SegmentAdminForm
+class RulePanel(InlinePanel):
+ def on_model_bound(self):
+ self.db_field = self.model._meta.get_field(
+ self.relation_name.replace('_related', 's'))
+ manager = getattr(self.model, self.relation_name)
+ self.related = manager.rel
+
+
class SegmentQuerySet(models.QuerySet):
def enabled(self):
return self.filter(status=self.model.STATUS_ENABLED)
-@python_2_unicode_compatible
class Segment(ClusterableModel):
"""The segment model."""
STATUS_ENABLED = 'enabled'
@@ -121,8 +127,8 @@ class Segment(ClusterableModel):
FieldPanel('randomisation_percent', classname='percent_field'),
], heading="Segment"),
MultiFieldPanel([
- InlinePanel(
- "{}s".format(rule_model._meta.db_table),
+ RulePanel(
+ "{}_related".format(rule_model._meta.db_table),
label='{}{}'.format(
rule_model._meta.verbose_name,
' ({})'.format(_('Static compatible')) if rule_model.static else ''
diff --git a/src/wagtail_personalisation/views.py b/src/wagtail_personalisation/views.py
index de421a4..0765230 100644
--- a/src/wagtail_personalisation/views.py
+++ b/src/wagtail_personalisation/views.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import csv
from django import forms
@@ -87,7 +85,10 @@ class SegmentModelAdmin(ModelAdmin):
'page_count', 'variant_count', 'statistics')
index_view_extra_js = ['js/commons.js', 'js/index.js']
index_view_extra_css = ['css/index.css']
- form_view_extra_js = ['js/commons.js', 'js/form.js']
+ form_view_extra_js = ['js/commons.js', 'js/form.js',
+ 'js/segment_form_control.js',
+ 'wagtailadmin/js/page-chooser-modal.js',
+ 'wagtailadmin/js/page-chooser.js']
form_view_extra_css = ['css/form.css']
def index_view(self, request):
diff --git a/src/wagtail_personalisation/wagtail_hooks.py b/src/wagtail_personalisation/wagtail_hooks.py
index a65e57c..24aecca 100644
--- a/src/wagtail_personalisation/wagtail_hooks.py
+++ b/src/wagtail_personalisation/wagtail_hooks.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import logging
from django.conf.urls import include, url
@@ -227,8 +225,7 @@ class PersonalisedPagesSummaryPanel(PagesSummaryItem):
order = 2100
def render(self):
- page_count = models.PersonalisablePageMetadata.objects.filter(
- segment__isnull=True).count()
+ page_count = models.PersonalisablePageMetadata.objects.filter(segment__isnull=True).count()
title = _("Personalised Page")
return mark_safe("""
diff --git a/tests/conftest.py b/tests/conftest.py
index 77e07e7..e677aeb 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import pytest
pytest_plugins = [
@@ -7,6 +5,11 @@ pytest_plugins = [
]
+@pytest.fixture(autouse=True)
+def enable_db_access(db):
+ pass
+
+
@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
from wagtail.core.models import Page, Site
diff --git a/tests/settings.py b/tests/settings.py
index 51125a7..1c2d0ee 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -1,6 +1,7 @@
-from __future__ import absolute_import, unicode_literals
-
import os
+from distutils.version import StrictVersion as V
+
+import django
DATABASES = {
'default': {
@@ -52,16 +53,27 @@ TEMPLATES = [
},
]
-MIDDLEWARE = (
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
- 'wagtail.core.middleware.SiteMiddleware',
-)
+def get_middleware_settings():
+ return (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+
+ 'wagtail.core.middleware.SiteMiddleware',
+ )
+
+
+# Django 1.10 started to use "MIDDLEWARE" instead of "MIDDLEWARE_CLASSES".
+if V(django.get_version()) < V('1.10'):
+ MIDDLEWARE_CLASSES = get_middleware_settings()
+else:
+ MIDDLEWARE = get_middleware_settings()
+
INSTALLED_APPS = (
'wagtail_personalisation',
diff --git a/tests/unit/test_models.py b/tests/unit/test_models.py
index d814f7b..0a7cd27 100644
--- a/tests/unit/test_models.py
+++ b/tests/unit/test_models.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import datetime
import pytest
@@ -8,7 +6,7 @@ from django.db.models import ProtectedError
from tests.factories.page import ContentPageFactory
from tests.factories.segment import SegmentFactory
from tests.site.pages import models
-from wagtail_personalisation.models import PersonalisablePageMetadata
+from wagtail_personalisation.models import PersonalisablePageMetadata, Segment
from wagtail_personalisation.rules import TimeRule
@@ -73,3 +71,10 @@ def test_sitemap_generation_for_canonical_pages_is_enabled(segmented_page):
def test_sitemap_generation_for_variants_is_disabled(segmented_page):
assert not segmented_page.personalisation_metadata.is_canonical
assert not segmented_page.get_sitemap_urls()
+
+
+@pytest.mark.django_db
+def test_segment_edit_view(site, client, django_user_model):
+ test_segment = Segment()
+ new_panel = test_segment.panels[1].children[0].bind_to_model(Segment)
+ assert new_panel.related.name == "wagtail_personalisation_timerules"
diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
index 1d0c182..f34704f 100644
--- a/tests/unit/test_utils.py
+++ b/tests/unit/test_utils.py
@@ -3,8 +3,14 @@ import pytest
from django.test import override_settings
from tests.factories.page import ContentPageFactory
+from wagtail.core.models import Page as WagtailPage
from wagtail_personalisation.utils import (
- can_delete_pages, get_client_ip, impersonate_other_page)
+ can_delete_pages, get_client_ip, impersonate_other_page, exclude_variants)
+
+
+class Metadata:
+ def __init__(self, is_canonical=True):
+ self.is_canonical = is_canonical
@pytest.fixture
@@ -64,3 +70,54 @@ def test_get_client_ip_custom_get_client_ip_function_does_not_exist(rf):
)
def test_get_client_ip_custom_get_client_ip_used(rf):
assert get_client_ip(rf.get('/')) == '123.123.123.123'
+
+
+def test_exclude_variants_with_pages_querysets():
+ '''
+ Test that excludes variant works for querysets
+ '''
+ for i in range(5):
+ page = WagtailPage(path="/" + str(i), depth=0, url_path="/", title="Hoi " + str(i))
+ page.save()
+ pages = WagtailPage.objects.all().order_by('id')
+
+ result = exclude_variants(pages)
+ assert type(result) == type(pages)
+ assert result == pages
+
+
+def test_exclude_variants_with_pages_querysets_not_canonical():
+ '''
+ Test that excludes variant works for querysets with
+ personalisation_metadata canonical False
+ '''
+ for i in range(5):
+ page = WagtailPage(path="/" + str(i), depth=0, url_path="/", title="Hoi " + str(i))
+ page.save()
+ pages = WagtailPage.objects.all().order_by('id')
+ # add variants
+ for page in pages:
+ page.personalisation_metadata = Metadata(is_canonical=False)
+ page.save()
+
+ result = exclude_variants(pages)
+ assert type(result) == type(pages)
+ assert result.count() == 0
+
+
+def test_exclude_variants_with_pages_querysets_meta_none():
+ '''
+ Test that excludes variant works for querysets with meta as none
+ '''
+ for i in range(5):
+ page = WagtailPage(path="/" + str(i), depth=0, url_path="/", title="Hoi " + str(i))
+ page.save()
+ pages = WagtailPage.objects.all().order_by('id')
+ # add variants
+ for page in pages:
+ page.personalisation_metadata = None
+ page.save()
+
+ result = exclude_variants(pages)
+ assert type(result) == type(pages)
+ assert result == pages
diff --git a/tox.ini b/tox.ini
index 159f784..a3c0211 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py{36}-django{20}-wagtail{20,21}{,-geoip2},lint
+envlist = py{36}-django{111,20}-wagtail{20,21,22}{,-geoip2},lint
[testenv]
basepython = python3.6
@@ -9,7 +9,9 @@ deps =
django20: django>=2.0,<2.1
wagtail20: wagtail>=2.0,<2.1
wagtail21: wagtail>=2.1,<2.2
+ wagtail22: wagtail>=2.2,<2.3
geoip2: geoip2
+ django111: django>=1.11,<1.12
[testenv:coverage-report]
basepython = python3.6
@@ -21,7 +23,7 @@ commands =
[testenv:lint]
basepython = python3.6
-deps = flake8
+deps = flake8==3.5.0
commands =
flake8 src tests setup.py
isort -q --recursive --diff src/ tests/