diff --git a/src/personalisation/admin.py b/src/personalisation/admin.py index 7d710bba..b2af20c1 100644 --- a/src/personalisation/admin.py +++ b/src/personalisation/admin.py @@ -24,10 +24,16 @@ class VisitCountRuleAdminInline(admin.TabularInline): model = models.VisitCountRule extra = 0 +class CloudfrontDeviceTypeRuleAdminInline(admin.TabularInline): + """Inline the Cloudfront DeviceType rule into the + administration interface for segments""" + model = models.CloudfrontDeviceTypeRule + extra = 0 + class SegmentAdmin(admin.ModelAdmin): """Add the inlines to the Segment admin interface""" - inlines = (TimeRuleAdminInline, + inlines = (TimeRuleAdminInline, CloudfrontDeviceTypeRuleAdminInline, ReferralRuleAdminInline, VisitCountRuleAdminInline) diff --git a/src/personalisation/migrations/0005_cloudfrontdevicetyperule.py b/src/personalisation/migrations/0005_cloudfrontdevicetyperule.py new file mode 100644 index 00000000..a0e0d1b1 --- /dev/null +++ b/src/personalisation/migrations/0005_cloudfrontdevicetyperule.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-12-12 18:45 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('personalisation', '0004_segment_persistent'), + ] + + operations = [ + migrations.CreateModel( + name='CloudfrontDeviceTypeRule', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_tablet', models.BooleanField(default=False)), + ('is_smartphone', models.BooleanField(default=False)), + ('is_desktop', models.BooleanField(default=False)), + ('is_smarttv', models.BooleanField(default=False)), + ('segment', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='personalisation_cloudfrontdevicetyperule_related', related_query_name='personalisation_cloudfrontdevicetyperules', to='personalisation.Segment')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/src/personalisation/models.py b/src/personalisation/models.py index ac2a4ced..25fb8d74 100644 --- a/src/personalisation/models.py +++ b/src/personalisation/models.py @@ -93,6 +93,52 @@ def __str__(self): return 'Referral Rule' +@python_2_unicode_compatible +class CloudfrontDeviceTypeRule(AbstractBaseRule): + """Referral rule to segment users based on a their device type as it was + detected by Cloudfront""" + + is_tablet = models.BooleanField(default=False) + is_smartphone = models.BooleanField(default=False) + is_desktop = models.BooleanField(default=False) + is_smarttv = models.BooleanField(default=False) + + panels = [ + FieldPanel('is_tablet'), + FieldPanel('is_smartphone'), + FieldPanel('is_desktop'), + FieldPanel('is_smarttv'), + ] + + def __init__(self, *args, **kwargs): + super(CloudfrontDeviceTypeRule, self).__init__(*args, **kwargs) + + def test_user(self, request): + """test different cloudfront headers. If those are not available, + False will be returned""" + + return ( + self.is_smartphone == self._header_value(request, + 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER') + or self.is_tablet == self._header_value(request, + 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER') + or self.is_desktop == self._header_value(request, + 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER') + or self.is_smarttv == self._header_value(request, + 'HTTP_CLOUDFRONT_IS_SMARTTV_VIEWER') + ) + + def _header_value(self, request, header): + header_value = request.META.get(header, None), + + if None not in header_value: + return True if 'true' in header_value else False + return None + + def __str__(self): + return 'Cloudfront Device Type Rule' + + @python_2_unicode_compatible class VisitCountRule(AbstractBaseRule): """Visit count rule to segment users based on amount of visits"""