Merge branch 'master' into feature/WXP-53-front-end-segment-bouwer
This commit is contained in:
32
README.rst
32
README.rst
@@ -1,4 +1,34 @@
|
|||||||
Wagtail personalisation module
|
Wagtail personalisation module
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
WIP
|
Personalisation module for Wagtail. This project is still work in progresss.
|
||||||
|
|
||||||
|
|
||||||
|
Instructions
|
||||||
|
------------
|
||||||
|
To install the package with pip::
|
||||||
|
|
||||||
|
pip install wagtail-personalisation
|
||||||
|
|
||||||
|
Next, include the ``personalisation`` and ``wagtail.contrib.modeladmin`` app in your project's ``INSTALLED_APPS``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
# ...
|
||||||
|
'wagtail.contrib.modeladmin',
|
||||||
|
'personalisation',
|
||||||
|
# ...
|
||||||
|
]
|
||||||
|
|
||||||
|
Last but not least, add ``personalisation.middleware.SegmentMiddleware`` to your project's ``MIDDLEWARE``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
# ...
|
||||||
|
'personalisation.middleware.SegmentMiddleware',
|
||||||
|
# ...
|
||||||
|
]
|
||||||
|
|
||||||
|
Make sure that ``django.contrib.sessions.middleware.SessionMiddleware`` has been added in first, this is a prerequisite for this project.
|
1
setup.py
1
setup.py
@@ -28,6 +28,7 @@ setup(
|
|||||||
'Topic :: Internet :: WWW/HTTP :: Site Management',
|
'Topic :: Internet :: WWW/HTTP :: Site Management',
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
'django-model-utils==2.6',
|
||||||
'wagtail>=1.7',
|
'wagtail>=1.7',
|
||||||
]
|
]
|
||||||
)
|
)
|
17
src/personalisation/admin.py
Normal file
17
src/personalisation/admin.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from personalisation import models
|
||||||
|
|
||||||
|
class TimeRuleAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'start_time', 'end_time')
|
||||||
|
|
||||||
|
class TimeRuleAdminInline(admin.TabularInline):
|
||||||
|
model = models.TimeRule
|
||||||
|
|
||||||
|
class SegmentAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['name']
|
||||||
|
inlines = (TimeRuleAdminInline,)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(models.TimeRule, TimeRuleAdmin)
|
||||||
|
admin.site.register(models.Segment, SegmentAdmin)
|
@@ -1,3 +1,5 @@
|
|||||||
|
from personalisation.models import Segment, AbstractBaseRule, TimeRule
|
||||||
|
|
||||||
class SegmentMiddleware(object):
|
class SegmentMiddleware(object):
|
||||||
"""Middleware for testing and putting a user in a segment"""
|
"""Middleware for testing and putting a user in a segment"""
|
||||||
|
|
||||||
@@ -5,9 +7,21 @@ class SegmentMiddleware(object):
|
|||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
request.session['segmented'] = True
|
segments = Segment.objects.all().filter(status="live")
|
||||||
|
|
||||||
|
chosen_segments = []
|
||||||
|
|
||||||
|
for segment in segments:
|
||||||
|
result = False
|
||||||
|
rules = AbstractBaseRule.objects.filter(segment=segment).select_subclasses()
|
||||||
|
for rule in rules:
|
||||||
|
result = rule.test_user()
|
||||||
|
if result:
|
||||||
|
chosen_segments.append(segment.encoded_name())
|
||||||
|
|
||||||
|
request.session['segments'] = chosen_segments
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
|
||||||
print(request.session['segmented'])
|
print(request.session['segments'])
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.3 on 2016-11-07 13:53
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalisation', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AbstractBaseRule',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TimeRule',
|
||||||
|
fields=[
|
||||||
|
('abstractbaserule_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='personalisation.AbstractBaseRule')),
|
||||||
|
('start_time', models.TimeField(verbose_name='Starting time')),
|
||||||
|
('end_time', models.TimeField(verbose_name='Ending time')),
|
||||||
|
],
|
||||||
|
bases=('personalisation.abstractbaserule',),
|
||||||
|
),
|
||||||
|
]
|
@@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.3 on 2016-11-07 14:12
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalisation', '0002_abstractbaserule_timerule'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='abstractbaserule',
|
||||||
|
name='segment',
|
||||||
|
field=models.ForeignKey(default='', on_delete=django.db.models.deletion.CASCADE, related_name='segment', to='personalisation.Segment'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
20
src/personalisation/migrations/0004_segment_status.py
Normal file
20
src/personalisation/migrations/0004_segment_status.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.3 on 2016-11-07 14:34
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalisation', '0003_abstractbaserule_segment'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='segment',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('disabled', 'Disabled'), ('live', 'Live'), ('completed', 'Completed')], default='disabled', max_length=20),
|
||||||
|
),
|
||||||
|
]
|
@@ -1,10 +1,14 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
from datetime import datetime, time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from modelcluster.models import ClusterableModel
|
from modelcluster.models import ClusterableModel
|
||||||
|
from model_utils.managers import InheritanceManager
|
||||||
from wagtail.wagtailadmin.edit_handlers import FieldPanel
|
from wagtail.wagtailadmin.edit_handlers import FieldPanel
|
||||||
|
|
||||||
|
|
||||||
@@ -14,6 +18,12 @@ Model for a new segment
|
|||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Segment(ClusterableModel):
|
class Segment(ClusterableModel):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
('disabled', 'Disabled'),
|
||||||
|
('live', 'Live'),
|
||||||
|
('completed', 'Completed'),
|
||||||
|
)
|
||||||
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="disabled")
|
||||||
|
|
||||||
panels = [
|
panels = [
|
||||||
FieldPanel('name'),
|
FieldPanel('name'),
|
||||||
@@ -21,3 +31,45 @@ class Segment(ClusterableModel):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def encoded_name(self):
|
||||||
|
return "".join(self.name.lower().split())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Base for creating rules to segment users with
|
||||||
|
"""
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class AbstractBaseRule(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
segment = models.ForeignKey(to=Segment, related_name="segment")
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
|
def test_user(self, request=None):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def return_segment_id(self):
|
||||||
|
return "".join(self.name.lower().split())
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Time rule to segment users with
|
||||||
|
"""
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class TimeRule(AbstractBaseRule):
|
||||||
|
start_time = models.TimeField(_("Starting time"))
|
||||||
|
end_time = models.TimeField(_("Ending time"))
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(TimeRule, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def test_user(self, request=None):
|
||||||
|
current_time = datetime.now().time()
|
||||||
|
starting_time = self.start_time
|
||||||
|
ending_time = self.end_time
|
||||||
|
|
||||||
|
return starting_time <= current_time <= ending_time
|
||||||
|
Reference in New Issue
Block a user