Skip to content

[fixes #14] Allow for standalone URL to be use as goals #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
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
5 changes: 5 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include LICENSE
include README.rst
include CHANGELOG.txt
recursive-include experiments/static *
recursive-include experiments/templates *
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This module supports the creation of A/B testing experiments within a Wagtail si
Installation
------------

wagtail-experiments is compatible with Wagtail 1.7, and Django 1.8 to 1.10. To install::
wagtail-experiments is compatible with Wagtail 2.3, and Django 2+ To install::

pip install wagtail-experiments

Expand Down
9 changes: 9 additions & 0 deletions createmigrations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python

import sys
import os

from django.core.management import execute_from_command_line

os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
execute_from_command_line([sys.argv[0], 'makemigrations'])
10 changes: 6 additions & 4 deletions experiments/admin_urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from __future__ import absolute_import, unicode_literals

from django.conf.urls import url
from django.urls import path
from experiments import views

app_name='experiments'

urlpatterns = [
url(r'^experiment/report/(\d+)/$', views.experiment_report, name='report'),
url(r'^experiment/select_winner/(\d+)/(\d+)/$', views.select_winner, name='select_winner'),
url(r'^experiment/report/preview/(\d+)/(\d+)/$', views.preview_for_report, name='preview_for_report'),
path('experiment/report/<int:experiment_id>/', views.experiment_report, name='report'),
path('experiment/select_winner/<int:experiment_id>/<int:variation_id>/', views.select_winner, name='select_winner'),
path('experiment/report/preview/<int:experiment_id>/<int:page_id>/', views.preview_for_report, name='preview_for_report'),
]
24 changes: 24 additions & 0 deletions experiments/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
MiddlewareMixin = object

from . models import Experiment
from .utils import get_user_id


class GoalURLMiddleware(MiddlewareMixin):
def process_request(self, request):
current_url = request.path
# does the current URL matches the goal URL for a live experiment?
experiments = Experiment.objects.filter(
goal_url__contains=current_url,
status='live'
)
if experiments.exists():
# let's complete all experiment that match this URL
user_id = get_user_id(request)
for experiment in experiments:
experiment.record_completion_for_user(user_id, request)
# If the current_url is not an experiment's goal_url, then don't do anything
return None
7 changes: 4 additions & 3 deletions experiments/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from django.db import migrations, models
import modelcluster.fields
import django.db.models.deletion


class Migration(migrations.Migration):
Expand All @@ -29,8 +30,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)),
('name', models.CharField(max_length=255)),
('slug', models.SlugField(max_length=255)),
('control_page', models.ForeignKey(related_name='+', to='wagtailcore.Page')),
('goal', models.ForeignKey(related_name='+', to='wagtailcore.Page')),
('control_page', models.ForeignKey(related_name='+', to='wagtailcore.Page', on_delete=django.db.models.deletion.SET_NULL)),
('goal', models.ForeignKey(related_name='+', to='wagtailcore.Page', on_delete=django.db.models.deletion.SET_NULL)),
],
options={
'abstract': False,
Expand All @@ -44,6 +45,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='alternative',
name='page',
field=models.ForeignKey(related_name='+', to='wagtailcore.Page'),
field=models.ForeignKey(related_name='+', to='wagtailcore.Page', on_delete=django.db.models.deletion.SET_NULL),
),
]
5 changes: 3 additions & 2 deletions experiments/migrations/0002_experiment_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
Expand All @@ -19,8 +20,8 @@ class Migration(migrations.Migration):
('date', models.DateField()),
('participant_count', models.PositiveIntegerField(default=0)),
('completion_count', models.PositiveIntegerField(default=0)),
('experiment', models.ForeignKey(to='experiments.Experiment', related_name='history')),
('variation', models.ForeignKey(to='wagtailcore.Page', related_name='+')),
('experiment', models.ForeignKey(to='experiments.Experiment', related_name='history', on_delete=django.db.models.deletion.SET_NULL)),
('variation', models.ForeignKey(to='wagtailcore.Page', related_name='+', on_delete=django.db.models.deletion.SET_NULL)),
],
),
migrations.AlterUniqueTogether(
Expand Down
25 changes: 25 additions & 0 deletions experiments/migrations/0006_auto_20180213_1541.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2018-02-13 20:41
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('experiments', '0005_make_goal_optional'),
]

operations = [
migrations.AddField(
model_name='experiment',
name='goal_url',
field=models.CharField(blank=True, default='', max_length=255),
),
migrations.AlterField(
model_name='experiment',
name='status',
field=models.CharField(choices=[('draft', 'Draft'), ('live', 'Live'), ('completed', 'Completed')], db_index=True, default='draft', max_length=10),
),
]
34 changes: 34 additions & 0 deletions experiments/migrations/0007_auto_20181028_1516.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 2.1.2 on 2018-10-28 20:16

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('experiments', '0006_auto_20180213_1541'),
]

operations = [
migrations.AlterField(
model_name='alternative',
name='page',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page'),
),
migrations.AlterField(
model_name='experiment',
name='control_page',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page'),
),
migrations.AlterField(
model_name='experimenthistory',
name='experiment',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='history', to='experiments.Experiment'),
),
migrations.AlterField(
model_name='experimenthistory',
name='variation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page'),
),
]
8 changes: 5 additions & 3 deletions experiments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from wagtail.wagtailadmin.edit_handlers import FieldPanel, PageChooserPanel, InlinePanel
from wagtail.wagtailcore.models import Orderable
from wagtail.admin.edit_handlers import FieldPanel, PageChooserPanel, InlinePanel
from wagtail.core.models import Orderable


BACKEND = None
Expand All @@ -36,7 +36,8 @@ class Experiment(ClusterableModel):
slug = models.SlugField(max_length=255)
control_page = models.ForeignKey('wagtailcore.Page', related_name='+', on_delete=models.CASCADE)
goal = models.ForeignKey('wagtailcore.Page', related_name='+', on_delete=models.SET_NULL, null=True, blank=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
goal_url = models.CharField(max_length=255, blank=True, default='')
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft', db_index=True)
winning_variation = models.ForeignKey('wagtailcore.Page', related_name='+', on_delete=models.SET_NULL, null=True)

panels = [
Expand All @@ -45,6 +46,7 @@ class Experiment(ClusterableModel):
PageChooserPanel('control_page'),
InlinePanel('alternatives', label="Alternatives"),
PageChooserPanel('goal'),
FieldPanel('goal_url'),
FieldPanel('status'),
]

Expand Down
4 changes: 2 additions & 2 deletions experiments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import ugettext as _

from wagtail.wagtailadmin import messages
from wagtail.wagtailcore.models import Page
from wagtail.admin import messages
from wagtail.core.models import Page

from .models import Experiment, get_backend
from .utils import get_user_id, impersonate_other_page, percentage
Expand Down
8 changes: 4 additions & 4 deletions experiments/wagtail_hooks.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import absolute_import, unicode_literals

from django.conf.urls import include, url
from django.urls import include, path
from django.contrib.admin.utils import quote
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from experiments import admin_urls
from wagtail.contrib.modeladmin.helpers import ButtonHelper
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from wagtail.contrib.modeladmin.views import CreateView, EditView
from wagtail.wagtailcore import hooks
from wagtail.core import hooks

from .models import Experiment
from .utils import get_user_id, impersonate_other_page
Expand All @@ -17,7 +17,7 @@
@hooks.register('register_admin_urls')
def register_admin_urls():
return [
url(r'^experiments/', include(admin_urls, app_name='experiments', namespace='experiments')),
path('experiments/', include(admin_urls, namespace='experiments')),
]


Expand Down
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setup(
name='wagtail-experiments',
version='0.1.2',
version='0.1.3',
description="A/B testing for Wagtail",
author='Matthew Westcott',
author_email='[email protected]',
Expand All @@ -20,11 +20,12 @@
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Framework :: Django',
],
)
3 changes: 2 additions & 1 deletion tests/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
Expand All @@ -14,7 +15,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='SimplePage',
fields=[
('page_ptr', models.OneToOneField(primary_key=True, parent_link=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
('page_ptr', models.OneToOneField(primary_key=True, parent_link=True, to='wagtailcore.Page', auto_created=True, serialize=False, on_delete=django.db.models.deletion.SET_NULL)),
('body', models.TextField()),
],
options={
Expand Down
19 changes: 19 additions & 0 deletions tests/migrations/0003_auto_20181028_1516.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.1.2 on 2018-10-28 20:16

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('tests', '0002_simplepagerelatedlink'),
]

operations = [
migrations.AlterField(
model_name='simplepage',
name='page_ptr',
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page'),
),
]
2 changes: 1 addition & 1 deletion tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.db import models

from modelcluster.fields import ParentalKey
from wagtail.wagtailcore.models import Page, Orderable
from wagtail.core.models import Page, Orderable


class SimplePage(Page):
Expand Down
21 changes: 10 additions & 11 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,37 +54,36 @@
'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.wagtailcore.middleware.SiteMiddleware',
'wagtail.core.middleware.SiteMiddleware',
'experiments.middleware.GoalURLMiddleware',
)
else:
MIDDLEWARE_CLASSES = (
'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.wagtailcore.middleware.SiteMiddleware',
'wagtail.core.middleware.SiteMiddleware',
)

INSTALLED_APPS = (
'experiments',
'tests',

'wagtail.contrib.modeladmin',
'wagtail.wagtailsearch',
'wagtail.wagtailsites',
'wagtail.wagtailusers',
'wagtail.wagtailimages',
'wagtail.wagtaildocs',
'wagtail.wagtailadmin',
'wagtail.wagtailcore',
'wagtail.search',
'wagtail.sites',
'wagtail.users',
'wagtail.images',
'wagtail.documents',
'wagtail.admin',
'wagtail.core',

'taggit',

Expand Down
Loading