Merge preakholt changes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,6 +13,7 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
build/
|
build/
|
||||||
|
ve/
|
||||||
dist/
|
dist/
|
||||||
htmlcov/
|
htmlcov/
|
||||||
docs/_build
|
docs/_build
|
||||||
|
@ -14,6 +14,8 @@ matrix:
|
|||||||
env: TOXENV=py36-django20-wagtail21
|
env: TOXENV=py36-django20-wagtail21
|
||||||
- python: 3.6
|
- python: 3.6
|
||||||
env: TOXENV=py36-django20-wagtail21-geoip2
|
env: TOXENV=py36-django20-wagtail21-geoip2
|
||||||
|
- python: 3.6
|
||||||
|
env: TOXENV=py36-django111-wagtail22
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install tox codecov
|
- pip install tox codecov
|
||||||
|
10
CHANGES
10
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
|
0.12.0
|
||||||
==================
|
==================
|
||||||
- Fix Django version classifier in setup.py
|
- Fix Django version classifier in setup.py
|
||||||
|
|
||||||
0.12.0
|
0.12.0
|
||||||
==================
|
==================
|
||||||
- Merged forks of Torchbox and Praekelt
|
- Merged forks of Torchbox and Praekolt
|
||||||
- Wagtail 2 compatibility
|
- Wagtail 2 compatibility
|
||||||
- Makefile adjustments for portability
|
- Makefile adjustments for portability
|
||||||
- Adds simple segment forcing for superusers
|
- Adds simple segment forcing for superusers
|
||||||
|
@ -54,7 +54,7 @@ master_doc = 'index'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = 'wagtail-personalisation'
|
project = 'wagtail-personalisation'
|
||||||
copyright = '2018, Lab Digital BV'
|
copyright = '2019, Lab Digital BV'
|
||||||
author = 'Lab Digital BV'
|
author = 'Lab Digital BV'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
6
setup.py
6
setup.py
@ -2,7 +2,7 @@ import re
|
|||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
install_requires = [
|
install_requires = [
|
||||||
'wagtail>=2.0',
|
'wagtail>=2.0,<2.3',
|
||||||
'user-agents>=1.1.0',
|
'user-agents>=1.1.0',
|
||||||
'wagtailfontawesome>=1.1.3',
|
'wagtailfontawesome>=1.1.3',
|
||||||
'pycountry',
|
'pycountry',
|
||||||
@ -20,7 +20,7 @@ tests_require = [
|
|||||||
'pytest-pythonpath==0.7.2',
|
'pytest-pythonpath==0.7.2',
|
||||||
'pytest-sugar==0.9.1',
|
'pytest-sugar==0.9.1',
|
||||||
'pytest==3.4.2',
|
'pytest==3.4.2',
|
||||||
'wagtail_factories==1.0.0',
|
'wagtail_factories==1.1.0',
|
||||||
'pytest-mock==1.6.3',
|
'pytest-mock==1.6.3',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ setup(
|
|||||||
license='MIT',
|
license='MIT',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 2 - Pre-Alpha',
|
'Development Status :: 5 - Production/Stable',
|
||||||
'Environment :: Web Environment',
|
'Environment :: Web Environment',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
|
import wagtail
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.template.defaultfilters import slugify
|
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.functional import cached_property
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from modelcluster.models import ClusterableModel
|
from modelcluster.models import ClusterableModel
|
||||||
import wagtail
|
|
||||||
from wagtail.admin.edit_handlers import (
|
from wagtail.admin.edit_handlers import (
|
||||||
FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel)
|
FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel)
|
||||||
from wagtail.core.models import Page
|
from wagtail.core.models import Page
|
||||||
@ -21,12 +20,19 @@ from wagtail_personalisation.utils import count_active_days
|
|||||||
from .forms import SegmentAdminForm
|
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):
|
class SegmentQuerySet(models.QuerySet):
|
||||||
def enabled(self):
|
def enabled(self):
|
||||||
return self.filter(status=self.model.STATUS_ENABLED)
|
return self.filter(status=self.model.STATUS_ENABLED)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Segment(ClusterableModel):
|
class Segment(ClusterableModel):
|
||||||
"""The segment model."""
|
"""The segment model."""
|
||||||
STATUS_ENABLED = 'enabled'
|
STATUS_ENABLED = 'enabled'
|
||||||
@ -121,8 +127,8 @@ class Segment(ClusterableModel):
|
|||||||
FieldPanel('randomisation_percent', classname='percent_field'),
|
FieldPanel('randomisation_percent', classname='percent_field'),
|
||||||
], heading="Segment"),
|
], heading="Segment"),
|
||||||
MultiFieldPanel([
|
MultiFieldPanel([
|
||||||
InlinePanel(
|
RulePanel(
|
||||||
"{}s".format(rule_model._meta.db_table),
|
"{}_related".format(rule_model._meta.db_table),
|
||||||
label='{}{}'.format(
|
label='{}{}'.format(
|
||||||
rule_model._meta.verbose_name,
|
rule_model._meta.verbose_name,
|
||||||
' ({})'.format(_('Static compatible')) if rule_model.static else ''
|
' ({})'.format(_('Static compatible')) if rule_model.static else ''
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
@ -87,7 +85,10 @@ class SegmentModelAdmin(ModelAdmin):
|
|||||||
'page_count', 'variant_count', 'statistics')
|
'page_count', 'variant_count', 'statistics')
|
||||||
index_view_extra_js = ['js/commons.js', 'js/index.js']
|
index_view_extra_js = ['js/commons.js', 'js/index.js']
|
||||||
index_view_extra_css = ['css/index.css']
|
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']
|
form_view_extra_css = ['css/form.css']
|
||||||
|
|
||||||
def index_view(self, request):
|
def index_view(self, request):
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
@ -227,8 +225,7 @@ class PersonalisedPagesSummaryPanel(PagesSummaryItem):
|
|||||||
order = 2100
|
order = 2100
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
page_count = models.PersonalisablePageMetadata.objects.filter(
|
page_count = models.PersonalisablePageMetadata.objects.filter(segment__isnull=True).count()
|
||||||
segment__isnull=True).count()
|
|
||||||
title = _("Personalised Page")
|
title = _("Personalised Page")
|
||||||
return mark_safe("""
|
return mark_safe("""
|
||||||
<li class="icon icon-fa-file-o">
|
<li class="icon icon-fa-file-o">
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
pytest_plugins = [
|
pytest_plugins = [
|
||||||
@ -7,6 +5,11 @@ pytest_plugins = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def enable_db_access(db):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def django_db_setup(django_db_setup, django_db_blocker):
|
def django_db_setup(django_db_setup, django_db_blocker):
|
||||||
from wagtail.core.models import Page, Site
|
from wagtail.core.models import Page, Site
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from distutils.version import StrictVersion as V
|
||||||
|
|
||||||
|
import django
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
@ -52,16 +53,27 @@ TEMPLATES = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = (
|
|
||||||
|
def get_middleware_settings():
|
||||||
|
return (
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
|
||||||
'wagtail.core.middleware.SiteMiddleware',
|
'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 = (
|
INSTALLED_APPS = (
|
||||||
'wagtail_personalisation',
|
'wagtail_personalisation',
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -8,7 +6,7 @@ from django.db.models import ProtectedError
|
|||||||
from tests.factories.page import ContentPageFactory
|
from tests.factories.page import ContentPageFactory
|
||||||
from tests.factories.segment import SegmentFactory
|
from tests.factories.segment import SegmentFactory
|
||||||
from tests.site.pages import models
|
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
|
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):
|
def test_sitemap_generation_for_variants_is_disabled(segmented_page):
|
||||||
assert not segmented_page.personalisation_metadata.is_canonical
|
assert not segmented_page.personalisation_metadata.is_canonical
|
||||||
assert not segmented_page.get_sitemap_urls()
|
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"
|
||||||
|
@ -3,8 +3,14 @@ import pytest
|
|||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from tests.factories.page import ContentPageFactory
|
from tests.factories.page import ContentPageFactory
|
||||||
|
from wagtail.core.models import Page as WagtailPage
|
||||||
from wagtail_personalisation.utils import (
|
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
|
@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):
|
def test_get_client_ip_custom_get_client_ip_used(rf):
|
||||||
assert get_client_ip(rf.get('/')) == '123.123.123.123'
|
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
|
||||||
|
6
tox.ini
6
tox.ini
@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py{36}-django{20}-wagtail{20,21}{,-geoip2},lint
|
envlist = py{36}-django{111,20}-wagtail{20,21,22}{,-geoip2},lint
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
basepython = python3.6
|
basepython = python3.6
|
||||||
@ -9,7 +9,9 @@ deps =
|
|||||||
django20: django>=2.0,<2.1
|
django20: django>=2.0,<2.1
|
||||||
wagtail20: wagtail>=2.0,<2.1
|
wagtail20: wagtail>=2.0,<2.1
|
||||||
wagtail21: wagtail>=2.1,<2.2
|
wagtail21: wagtail>=2.1,<2.2
|
||||||
|
wagtail22: wagtail>=2.2,<2.3
|
||||||
geoip2: geoip2
|
geoip2: geoip2
|
||||||
|
django111: django>=1.11,<1.12
|
||||||
|
|
||||||
[testenv:coverage-report]
|
[testenv:coverage-report]
|
||||||
basepython = python3.6
|
basepython = python3.6
|
||||||
@ -21,7 +23,7 @@ commands =
|
|||||||
|
|
||||||
[testenv:lint]
|
[testenv:lint]
|
||||||
basepython = python3.6
|
basepython = python3.6
|
||||||
deps = flake8
|
deps = flake8==3.5.0
|
||||||
commands =
|
commands =
|
||||||
flake8 src tests setup.py
|
flake8 src tests setup.py
|
||||||
isort -q --recursive --diff src/ tests/
|
isort -q --recursive --diff src/ tests/
|
||||||
|
Reference in New Issue
Block a user