From f74dad0b8be277a48c19a6edd52440ebde935bc5 Mon Sep 17 00:00:00 2001 From: Jasper Berghoef Date: Thu, 10 Nov 2016 16:02:47 +0100 Subject: [PATCH] Per page visit counting! --- src/personalisation/middleware.py | 19 ++++++++++-- .../0022_visitcountrule_counted_page.py | 22 ++++++++++++++ .../migrations/0023_auto_20161110_1454.py | 21 ++++++++++++++ src/personalisation/models.py | 29 +++++++++++++++---- src/personalisation/wagtail_hooks.py | 29 +++++++++++++++++-- 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 src/personalisation/migrations/0022_visitcountrule_counted_page.py create mode 100644 src/personalisation/migrations/0023_auto_20161110_1454.py diff --git a/src/personalisation/middleware.py b/src/personalisation/middleware.py index 3f1ecd2..5039770 100644 --- a/src/personalisation/middleware.py +++ b/src/personalisation/middleware.py @@ -16,9 +16,11 @@ class SegmentMiddleware(object): if request.path.startswith('/admin/') or request.path.startswith('/django-admin/'): return self.get_response(request) + if 'visit_count' not in request.session: + request.session['visit_count'] = [] + if 'segments' not in request.session: request.session['segments'] = [] - request.session['visit_count'] = 1 segments = Segment.objects.all().filter(status='enabled') @@ -30,6 +32,7 @@ class SegmentMiddleware(object): self.add_segment_to_user(segment, request) response = self.get_response(request) + logger.info("User has been added to the following segments: {}".format(request.session['segments'])) return response @@ -39,6 +42,19 @@ class SegmentMiddleware(object): for rule in rules: result = rule.test_user(request) + # Debug + if result and rule.__class__.__name__ == "TimeRule": + print("User segmented. Time between {} and {}.".format( + rule.start_time, + rule.end_time)) + if result and rule.__class__.__name__ == "ReferralRule": + print("User segmented. Referral matches {}.".format(rule.regex_string)) + if result and rule.__class__.__name__ == "VisitCountRule": + print("User segmented. Visited {} {} {} times.".format( + rule.counted_page, + rule.operator, + rule.count)) + if result is False: return False @@ -55,7 +71,6 @@ class SegmentMiddleware(object): return False if not check_if_segmented(segment): - # Clear segments session on browser close. segdict = { "encoded_name": segment.encoded_name(), "id": segment.pk, diff --git a/src/personalisation/migrations/0022_visitcountrule_counted_page.py b/src/personalisation/migrations/0022_visitcountrule_counted_page.py new file mode 100644 index 0000000..17541ce --- /dev/null +++ b/src/personalisation/migrations/0022_visitcountrule_counted_page.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-11-10 12:39 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0030_index_on_pagerevision_created_at'), + ('personalisation', '0021_auto_20161110_1325'), + ] + + operations = [ + migrations.AddField( + model_name='visitcountrule', + name='counted_page', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page'), + ), + ] diff --git a/src/personalisation/migrations/0023_auto_20161110_1454.py b/src/personalisation/migrations/0023_auto_20161110_1454.py new file mode 100644 index 0000000..2d48d1e --- /dev/null +++ b/src/personalisation/migrations/0023_auto_20161110_1454.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.3 on 2016-11-10 13:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('personalisation', '0022_visitcountrule_counted_page'), + ] + + operations = [ + migrations.AlterField( + model_name='visitcountrule', + name='counted_page', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailcore.Page'), + ), + ] diff --git a/src/personalisation/models.py b/src/personalisation/models.py index 1ae681a..b7ce9f7 100644 --- a/src/personalisation/models.py +++ b/src/personalisation/models.py @@ -11,7 +11,7 @@ from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from modelcluster.models import ClusterableModel from modelcluster.fields import ParentalKey -from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel +from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, PageChooserPanel from polymorphic.models import PolymorphicModel @@ -140,10 +140,18 @@ class VisitCountRule(AbstractBaseRule): ) operator = models.CharField(max_length=20, choices=OPERATOR_CHOICES, default="ht") count = models.PositiveSmallIntegerField(default=0, null=True) + counted_page = models.ForeignKey( + 'wagtailcore.Page', + null=False, + blank=False, + on_delete=models.CASCADE, + related_name='+', + ) panels = [ FieldPanel('operator'), FieldPanel('count'), + PageChooserPanel('counted_page'), ] def __init__(self, *args, **kwargs): @@ -152,15 +160,26 @@ class VisitCountRule(AbstractBaseRule): def test_user(self, request): operator = self.operator segment_count = self.count - visit_count = request.session.get('visit_count') - if operator == "more_than": + # TODO: Figure out a way to have a correct count before the middleware + # initiates the test function + + def get_visit_count(request): + """Search through the sessions to get the page visit count + corresponding to the request.""" + for page in request.session['visit_count']: + if page['path'] == request.path: + return page['count'] + + visit_count = get_visit_count(request) + + if visit_count and operator == "more_than": if visit_count > segment_count: return True - elif operator == "less_than": + elif visit_count and operator == "less_than": if visit_count < segment_count: return True - elif operator == "equal_to": + elif visit_count and operator == "equal_to": if visit_count == segment_count: return True return False diff --git a/src/personalisation/wagtail_hooks.py b/src/personalisation/wagtail_hooks.py index 333e0c0..a6e90dd 100644 --- a/src/personalisation/wagtail_hooks.py +++ b/src/personalisation/wagtail_hooks.py @@ -1,3 +1,5 @@ +import time + from django.conf.urls import include, url from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register from wagtail.contrib.modeladmin.views import IndexView @@ -34,12 +36,33 @@ modeladmin_register(SegmentModelAdmin) @hooks.register('before_serve_page') def set_visit_count(page, request, serve_args, serve_kwargs): """Update the users visit count before each page visit.""" + # Update the segment visit count for seg in request.session['segments']: segment = Segment.objects.get(pk=seg['id']) segment.visit_count = segment.visit_count + 1 segment.save() - if 'visit_count' not in request.session: - request.session['visit_count'] = 1 + # Update the page visit count + def create_new_counter(page): + """Create a new counter dict and place it in session storage.""" + countdict = { + "slug": page.slug, + "id": page.pk, + "path": page.url, + "count": 1, + } + request.session['visit_count'].append(countdict) + + if len(request.session['visit_count']) > 0: + for index, counter in enumerate(request.session['visit_count']): + if counter['id'] == page.pk: + # Counter already exisits. Increase the count value by 1. + newcount = counter['count'] + 1 + request.session['visit_count'][index]['count'] = newcount + request.session.modified = True + else: + # Counter doesn't exist. Create a new counter with count value 1. + create_new_counter(page) else: - request.session['visit_count'] = request.session.get('visit_count') + 1 + # No counters exist. Create a new counter with count value 1. + create_new_counter(page)