From ae97118c3fc1c277b69a91c5640cc35b1abd7b75 Mon Sep 17 00:00:00 2001 From: Kaitlyn Crawford Date: Fri, 2 Feb 2018 10:13:18 +0200 Subject: [PATCH 1/4] Store randomisation percentage on segment model --- src/wagtail_personalisation/models.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/wagtail_personalisation/models.py b/src/wagtail_personalisation/models.py index 2f9bfcf..9d27eb5 100644 --- a/src/wagtail_personalisation/models.py +++ b/src/wagtail_personalisation/models.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, unicode_literals 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 @@ -85,6 +86,16 @@ class Segment(ClusterableModel): matched_users_count = models.PositiveIntegerField(default=0, editable=False) matched_count_updated_at = models.DateTimeField(null=True, editable=False) + randomisation_percent = models.PositiveSmallIntegerField( + null=True, blank=True, default=None, + help_text=_( + "If this number is set each user matching the rules will " + "have this percentage chance of being placed in the segment." + ), validators=[ + MaxValueValidator(100), + MinValueValidator(0) + ]) + objects = SegmentQuerySet.as_manager() base_form_class = SegmentAdminForm @@ -100,6 +111,7 @@ class Segment(ClusterableModel): FieldPanel('match_any'), FieldPanel('type', widget=forms.RadioSelect), FieldPanel('count', classname='count_field'), + FieldPanel('randomisation_percent', classname='percent_field'), ], heading="Segment"), MultiFieldPanel([ InlinePanel( From 602919d2d490d79f94ecd51127224d3e35e950f4 Mon Sep 17 00:00:00 2001 From: Kaitlyn Crawford Date: Fri, 2 Feb 2018 10:14:18 +0200 Subject: [PATCH 2/4] Test randomisation percentage added to segments --- tests/unit/test_static_dynamic_segments.py | 34 +++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_static_dynamic_segments.py b/tests/unit/test_static_dynamic_segments.py index 686e89f..f5fce7c 100644 --- a/tests/unit/test_static_dynamic_segments.py +++ b/tests/unit/test_static_dynamic_segments.py @@ -13,7 +13,7 @@ from wagtail_personalisation.rules import (AbstractBaseRule, TimeRule, def form_with_data(segment, *rules): - model_fields = ['type', 'status', 'count', 'name', 'match_any'] + model_fields = ['type', 'status', 'count', 'name', 'match_any', 'randomisation_percent'] class TestSegmentAdminForm(SegmentAdminForm): class Meta: @@ -249,6 +249,38 @@ def test_dynamic_segment_with_non_static_rules_have_a_count(): assert form.is_valid(), form.errors +@pytest.mark.django_db +def test_randomisation_percentage_added_to_segment_at_creation(site, client, mocker, django_user_model): + segment = SegmentFactory.build(type=Segment.TYPE_STATIC) + segment.randomisation_percent = 80 + rule = VisitCountRule() + + form = form_with_data(segment, rule) + instance = form.save() + + assert instance.randomisation_percent == 80 + + +@pytest.mark.django_db +def test_randomisation_percentage_min_zero(site, client, mocker, django_user_model): + segment = SegmentFactory.build(type=Segment.TYPE_STATIC) + segment.randomisation_percent = -1 + rule = VisitCountRule() + + form = form_with_data(segment, rule) + assert not form.is_valid() + + +@pytest.mark.django_db +def test_randomisation_percentage_max_100(site, client, mocker, django_user_model): + segment = SegmentFactory.build(type=Segment.TYPE_STATIC) + segment.randomisation_percent = 101 + rule = VisitCountRule() + + form = form_with_data(segment, rule) + assert not form.is_valid() + + @pytest.mark.django_db def test_matched_user_count_added_to_segment_at_creation(site, client, mocker, django_user_model): django_user_model.objects.create(username='first') From 5c3acc66611f7b673f0875f18896d76df2d5e465 Mon Sep 17 00:00:00 2001 From: Kaitlyn Crawford Date: Fri, 2 Feb 2018 10:15:04 +0200 Subject: [PATCH 3/4] Display randomisation percentages on segment dashboard --- .../wagtail_personalisation/segment/dashboard.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/wagtail_personalisation/templates/modeladmin/wagtail_personalisation/segment/dashboard.html b/src/wagtail_personalisation/templates/modeladmin/wagtail_personalisation/segment/dashboard.html index 454a82e..d6858dd 100644 --- a/src/wagtail_personalisation/templates/modeladmin/wagtail_personalisation/segment/dashboard.html +++ b/src/wagtail_personalisation/templates/modeladmin/wagtail_personalisation/segment/dashboard.html @@ -70,6 +70,13 @@ {% endif %} + {% if segment.randomisation_percent is not None %} +
  • + {{ segment.randomisation_percent }} % + {% trans "Chance that visitors matching the rules are added to the segment" %} +
  • + {% endif %} + {% for rule in segment.get_rules %}
  • {{ rule.description.title }} From 29aa91477e834ac14ffb2dda2464181d1527744c Mon Sep 17 00:00:00 2001 From: Kaitlyn Crawford Date: Fri, 2 Feb 2018 10:15:20 +0200 Subject: [PATCH 4/4] Migrations --- .../0017_segment_randomisation_percent.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/wagtail_personalisation/migrations/0017_segment_randomisation_percent.py diff --git a/src/wagtail_personalisation/migrations/0017_segment_randomisation_percent.py b/src/wagtail_personalisation/migrations/0017_segment_randomisation_percent.py new file mode 100644 index 0000000..bd68335 --- /dev/null +++ b/src/wagtail_personalisation/migrations/0017_segment_randomisation_percent.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2018-01-31 16:12 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtail_personalisation', '0016_auto_20180125_0918'), + ] + + operations = [ + migrations.AddField( + model_name='segment', + name='randomisation_percent', + field=models.PositiveSmallIntegerField(blank=True, default=None, help_text='If this number is set each user matching the rules will have this percentage chance of being placed in the segment.', null=True, validators=[django.core.validators.MaxValueValidator(100), django.core.validators.MinValueValidator(0)]), + ), + ]