Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
7bf1bc3f19 | |||
4c60bcbe6b | |||
ad4f75d471 | |||
086168954d | |||
881090f2f9 | |||
d073c7d268 | |||
7200b5b4c4 | |||
6f97c76958 | |||
ecb4f928fb | |||
29aa91477e | |||
5c3acc6661 | |||
602919d2d4 | |||
ae97118c3f | |||
51774b939e | |||
908f85e295 | |||
99f9700ed0 | |||
7fa8ee1a46 | |||
5ad70d68f6 | |||
06bfe77901 | |||
d5e89d374b | |||
5b39e82f80 | |||
fbcebb43a4 | |||
ef271587ec | |||
786a8801b1 | |||
caf73aa43c | |||
4021d2c915 | |||
33f96af4a3 | |||
6299feb497 |
11
CHANGES
11
CHANGES
@ -1,3 +1,14 @@
|
|||||||
|
0.10.6
|
||||||
|
==================
|
||||||
|
- Accepts and stores randomisation percentage for segment
|
||||||
|
- Adds users to segment based on random number relative to percentage
|
||||||
|
|
||||||
|
0.10.5
|
||||||
|
==================
|
||||||
|
- Count how many users match a segments rules before saving the segment
|
||||||
|
- Stores count on the segment and displays in the dashboard
|
||||||
|
- Enables testing users against rules if there isn't an active request
|
||||||
|
|
||||||
0.10.0
|
0.10.0
|
||||||
==================
|
==================
|
||||||
- Adds static and dynamic segments
|
- Adds static and dynamic segments
|
||||||
|
@ -55,10 +55,10 @@ author = 'Lab Digital BV'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.10.4'
|
version = '0.10.6'
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.10.4'
|
release = '0.10.6'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.10.4
|
current_version = 0.10.6
|
||||||
commit = true
|
commit = true
|
||||||
tag = true
|
tag = true
|
||||||
tag_name = {new_version}
|
tag_name = {new_version}
|
||||||
|
2
setup.py
2
setup.py
@ -32,7 +32,7 @@ with open('README.rst') as fh:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='wagtail-personalisation-molo',
|
name='wagtail-personalisation-molo',
|
||||||
version='0.10.4',
|
version='0.10.6',
|
||||||
description='A forked version of Wagtail add-on for showing personalized content',
|
description='A forked version of Wagtail add-on for showing personalized content',
|
||||||
author='Praekelt.org',
|
author='Praekelt.org',
|
||||||
author_email='dev@praekeltfoundation.org',
|
author_email='dev@praekeltfoundation.org',
|
||||||
|
@ -184,13 +184,12 @@ class SessionSegmentsAdapter(BaseSegmentsAdapter):
|
|||||||
|
|
||||||
result = self._test_rules(segment_rules, self.request,
|
result = self._test_rules(segment_rules, self.request,
|
||||||
match_any=segment.match_any)
|
match_any=segment.match_any)
|
||||||
|
if result and segment.randomise_into_segment():
|
||||||
if result and segment.is_static and not segment.is_full:
|
if segment.is_static and not segment.is_full:
|
||||||
if self.request.user.is_authenticated():
|
if self.request.user.is_authenticated():
|
||||||
segment.static_users.add(self.request.user)
|
segment.static_users.add(self.request.user)
|
||||||
|
else:
|
||||||
if result:
|
additional_segments.append(segment)
|
||||||
additional_segments.append(segment)
|
|
||||||
|
|
||||||
self.set_segments(current_segments + additional_segments)
|
self.set_segments(current_segments + additional_segments)
|
||||||
self.update_visit_count()
|
self.update_visit_count()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from itertools import takewhile
|
from itertools import takewhile
|
||||||
|
|
||||||
@ -26,6 +27,29 @@ def user_from_data(user_id):
|
|||||||
|
|
||||||
|
|
||||||
class SegmentAdminForm(WagtailAdminModelForm):
|
class SegmentAdminForm(WagtailAdminModelForm):
|
||||||
|
|
||||||
|
def count_matching_users(self, rules, match_any):
|
||||||
|
""" Calculates how many users match the given static rules
|
||||||
|
"""
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
static_rules = [rule for rule in rules if rule.static]
|
||||||
|
|
||||||
|
if not static_rules:
|
||||||
|
return count
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
users = User.objects.filter(is_active=True, is_staff=False)
|
||||||
|
|
||||||
|
for user in users.iterator():
|
||||||
|
if match_any:
|
||||||
|
if any(rule.test_user(None, user) for rule in static_rules):
|
||||||
|
count += 1
|
||||||
|
elif all(rule.test_user(None, user) for rule in static_rules):
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(SegmentAdminForm, self).clean()
|
cleaned_data = super(SegmentAdminForm, self).clean()
|
||||||
Segment = self._meta.model
|
Segment = self._meta.model
|
||||||
@ -63,6 +87,16 @@ class SegmentAdminForm(WagtailAdminModelForm):
|
|||||||
if not self.instance.is_static:
|
if not self.instance.is_static:
|
||||||
self.instance.count = 0
|
self.instance.count = 0
|
||||||
|
|
||||||
|
if is_new:
|
||||||
|
rules = [
|
||||||
|
form.instance for formset in self.formsets.values()
|
||||||
|
for form in formset
|
||||||
|
if form not in formset.deleted_forms
|
||||||
|
]
|
||||||
|
self.instance.matched_users_count = self.count_matching_users(
|
||||||
|
rules, self.instance.match_any)
|
||||||
|
self.instance.matched_count_updated_at = datetime.now()
|
||||||
|
|
||||||
instance = super(SegmentAdminForm, self).save(*args, **kwargs)
|
instance = super(SegmentAdminForm, self).save(*args, **kwargs)
|
||||||
|
|
||||||
if is_new and instance.is_static and instance.all_rules_static:
|
if is_new and instance.is_static and instance.all_rules_static:
|
||||||
@ -85,7 +119,7 @@ class SegmentAdminForm(WagtailAdminModelForm):
|
|||||||
request.user = user
|
request.user = user
|
||||||
request.session = SessionStore(session_key=session.session_key)
|
request.session = SessionStore(session_key=session.session_key)
|
||||||
passes = adapter._test_rules(instance.get_rules(), request, instance.match_any)
|
passes = adapter._test_rules(instance.get_rules(), request, instance.match_any)
|
||||||
if passes:
|
if passes and instance.randomise_into_segment():
|
||||||
users_to_add.append(user)
|
users_to_add.append(user)
|
||||||
|
|
||||||
instance.static_users.add(*users_to_add)
|
instance.static_users.add(*users_to_add)
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.9 on 2018-01-25 09:18
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wagtail_personalisation', '0015_static_users'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='segment',
|
||||||
|
name='matched_count_updated_at',
|
||||||
|
field=models.DateTimeField(editable=False, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='segment',
|
||||||
|
name='matched_users_count',
|
||||||
|
field=models.PositiveIntegerField(default=0, editable=False),
|
||||||
|
),
|
||||||
|
]
|
@ -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)]),
|
||||||
|
),
|
||||||
|
]
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
import random
|
||||||
|
|
||||||
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.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.encoding import python_2_unicode_compatible
|
||||||
@ -82,6 +84,19 @@ class Segment(ClusterableModel):
|
|||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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()
|
objects = SegmentQuerySet.as_manager()
|
||||||
|
|
||||||
base_form_class = SegmentAdminForm
|
base_form_class = SegmentAdminForm
|
||||||
@ -97,6 +112,7 @@ class Segment(ClusterableModel):
|
|||||||
FieldPanel('match_any'),
|
FieldPanel('match_any'),
|
||||||
FieldPanel('type', widget=forms.RadioSelect),
|
FieldPanel('type', widget=forms.RadioSelect),
|
||||||
FieldPanel('count', classname='count_field'),
|
FieldPanel('count', classname='count_field'),
|
||||||
|
FieldPanel('randomisation_percent', classname='percent_field'),
|
||||||
], heading="Segment"),
|
], heading="Segment"),
|
||||||
MultiFieldPanel([
|
MultiFieldPanel([
|
||||||
InlinePanel(
|
InlinePanel(
|
||||||
@ -167,6 +183,19 @@ class Segment(ClusterableModel):
|
|||||||
if save:
|
if save:
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def randomise_into_segment(self):
|
||||||
|
""" Returns True if randomisation_percent is not set or it generates
|
||||||
|
a random number less than the randomisation_percent
|
||||||
|
This is so there is some randomisation in which users are added to the
|
||||||
|
segment
|
||||||
|
"""
|
||||||
|
if self.randomisation_percent is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if random.randint(1, 100) <= self.randomisation_percent:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class PersonalisablePageMetadata(ClusterableModel):
|
class PersonalisablePageMetadata(ClusterableModel):
|
||||||
"""The personalisable page model. Allows creation of variants with linked
|
"""The personalisable page model. Allows creation of variants with linked
|
||||||
|
@ -220,7 +220,12 @@ class VisitCountRule(AbstractBaseRule):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Visit count Rule')
|
verbose_name = _('Visit count Rule')
|
||||||
|
|
||||||
def test_user(self, request):
|
def test_user(self, request, user=None):
|
||||||
|
if user:
|
||||||
|
# This rule currently does not support testing a user directly
|
||||||
|
# TODO: Make this test a user directly when the rule uses
|
||||||
|
# historical data
|
||||||
|
return False
|
||||||
operator = self.operator
|
operator = self.operator
|
||||||
segment_count = self.count
|
segment_count = self.count
|
||||||
|
|
||||||
@ -276,7 +281,13 @@ class QueryRule(AbstractBaseRule):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Query Rule')
|
verbose_name = _('Query Rule')
|
||||||
|
|
||||||
def test_user(self, request):
|
def test_user(self, request, user=None):
|
||||||
|
if user:
|
||||||
|
# This rule currently does not support testing a user directly
|
||||||
|
# TODO: Make this test a user directly if/when the rule uses
|
||||||
|
# historical data
|
||||||
|
return False
|
||||||
|
|
||||||
return request.GET.get(self.parameter, '') == self.value
|
return request.GET.get(self.parameter, '') == self.value
|
||||||
|
|
||||||
def description(self):
|
def description(self):
|
||||||
|
@ -70,6 +70,13 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
{% if segment.randomisation_percent is not None %}
|
||||||
|
<li class="stat_card">
|
||||||
|
<span>{{ segment.randomisation_percent }} %</span>
|
||||||
|
{% trans "Chance that visitors matching the rules are added to the segment" %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% for rule in segment.get_rules %}
|
{% for rule in segment.get_rules %}
|
||||||
<li class="stat_card {{ rule.encoded_name }}">
|
<li class="stat_card {{ rule.encoded_name }}">
|
||||||
{{ rule.description.title }}
|
{{ rule.description.title }}
|
||||||
@ -80,6 +87,11 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if segment.matched_users_count > 0 %}
|
||||||
|
<li class="stat_card">
|
||||||
|
<span class="icon icon-fa-user"> {{ segment.matched_users_count }} {% trans "user" %}{{ segment.matched_users_count|pluralize }}</span> {% trans "were possible matches for this segment at creation" %}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -8,11 +8,12 @@ from django.forms.models import model_to_dict
|
|||||||
from tests.factories.segment import SegmentFactory
|
from tests.factories.segment import SegmentFactory
|
||||||
from wagtail_personalisation.forms import SegmentAdminForm
|
from wagtail_personalisation.forms import SegmentAdminForm
|
||||||
from wagtail_personalisation.models import Segment
|
from wagtail_personalisation.models import Segment
|
||||||
from wagtail_personalisation.rules import TimeRule, VisitCountRule
|
from wagtail_personalisation.rules import (AbstractBaseRule, TimeRule,
|
||||||
|
VisitCountRule)
|
||||||
|
|
||||||
|
|
||||||
def form_with_data(segment, *rules):
|
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 TestSegmentAdminForm(SegmentAdminForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -246,3 +247,301 @@ def test_dynamic_segment_with_non_static_rules_have_a_count():
|
|||||||
)
|
)
|
||||||
form = form_with_data(segment, rule)
|
form = form_with_data(segment, rule)
|
||||||
assert form.is_valid(), form.errors
|
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_in_segment_if_random_is_below_percentage(site, client, mocker, user):
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, count=1,
|
||||||
|
randomisation_percent=40)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
mocker.patch('random.randint', return_value=39)
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
assert user in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_not_in_segment_if_random_is_above_percentage(site, client, mocker, user):
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, count=1,
|
||||||
|
randomisation_percent=40)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
mocker.patch('random.randint', return_value=41)
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
assert user not in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_not_in_segment_if_percentage_is_0(site, client, mocker, user):
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, count=1,
|
||||||
|
randomisation_percent=0)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
assert user not in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_always_in_segment_if_percentage_is_100(site, client, mocker, user):
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, count=1,
|
||||||
|
randomisation_percent=100)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
assert user in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_not_added_to_static_segment_at_creation_if_random_above_percent(site, client, mocker, user):
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
mocker.patch('random.randint', return_value=41)
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, randomisation_percent=40)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
assert user not in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_added_to_static_segment_at_creation_if_random_below_percent(site, client, mocker, user):
|
||||||
|
session = client.session
|
||||||
|
session.save()
|
||||||
|
client.force_login(user)
|
||||||
|
client.get(site.root_page.url)
|
||||||
|
|
||||||
|
mocker.patch('random.randint', return_value=39)
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC, randomisation_percent=40)
|
||||||
|
rule = VisitCountRule(counted_page=site.root_page)
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
assert user in instance.static_users.all()
|
||||||
|
|
||||||
|
|
||||||
|
@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')
|
||||||
|
django_user_model.objects.create(username='second')
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
rule = VisitCountRule()
|
||||||
|
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
mock_test_user = mocker.patch('wagtail_personalisation.rules.VisitCountRule.test_user', return_value=True)
|
||||||
|
instance = form.save()
|
||||||
|
|
||||||
|
assert mock_test_user.call_count == 2
|
||||||
|
instance.matched_users_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_users_matching_static_rules(site, client, django_user_model):
|
||||||
|
class TestStaticRule(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
return True
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second')
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
rule = TestStaticRule()
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([rule], True) is 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_matching_users_excludes_staff(site, client, django_user_model):
|
||||||
|
class TestStaticRule(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
return True
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second', is_staff=True)
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
rule = TestStaticRule()
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([rule], True) is 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_matching_users_excludes_inactive(site, client, django_user_model):
|
||||||
|
class TestStaticRule(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
return True
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second', is_active=False)
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
rule = TestStaticRule()
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([rule], True) is 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_matching_users_only_counts_static_rules(site, client, django_user_model):
|
||||||
|
class TestStaticRule(AbstractBaseRule):
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
return True
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second')
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
rule = TestStaticRule()
|
||||||
|
form = form_with_data(segment, rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([rule], True) is 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_matching_users_handles_match_any(site, client, django_user_model):
|
||||||
|
class TestStaticRuleFirst(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
if user.username == 'first':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
class TestStaticRuleSecond(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
if user.username == 'second':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second')
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
first_rule = TestStaticRuleFirst()
|
||||||
|
second_rule = TestStaticRuleSecond()
|
||||||
|
form = form_with_data(segment, first_rule, second_rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([first_rule, second_rule], True) is 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_count_matching_users_handles_match_all(site, client, django_user_model):
|
||||||
|
class TestStaticRuleFirst(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
if user.username == 'first':
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
class TestStaticRuleContainsS(AbstractBaseRule):
|
||||||
|
static = True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'wagtail_personalisation'
|
||||||
|
|
||||||
|
def test_user(self, request, user):
|
||||||
|
if 's' in user.username:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
django_user_model.objects.create(username='first')
|
||||||
|
django_user_model.objects.create(username='second')
|
||||||
|
|
||||||
|
segment = SegmentFactory.build(type=Segment.TYPE_STATIC)
|
||||||
|
first_rule = TestStaticRuleFirst()
|
||||||
|
s_rule = TestStaticRuleContainsS()
|
||||||
|
form = form_with_data(segment, first_rule, s_rule)
|
||||||
|
|
||||||
|
assert form.count_matching_users([first_rule, s_rule], False) is 1
|
||||||
|
Reference in New Issue
Block a user