Skip to content

Commit 03f18d4

Browse files
committed
Added visit page view
Fixes #74 Allows frontend users to submit page views and retrieve segments while behind a cache or CDN.
1 parent 59b6e7f commit 03f18d4

File tree

4 files changed

+113
-3
lines changed

4 files changed

+113
-3
lines changed

src/wagtail_personalisation/adapters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def check_if_segmented(item):
131131
segdict = create_segment_dictionary(segment)
132132
self.request.session['segments'].append(segdict)
133133

134-
def add_page_visit(self, page):
134+
def add_page_visit(self, page, path=None):
135135
"""Mark the page as visited by the user"""
136136
visit_count = self.request.session.setdefault('visit_count', [])
137137
page_visits = [visit for visit in visit_count if visit['id'] == page.pk]
@@ -144,7 +144,7 @@ def add_page_visit(self, page):
144144
visit_count.append({
145145
'slug': page.slug,
146146
'id': page.pk,
147-
'path': self.request.path,
147+
'path': path or self.request.path,
148148
'count': 1,
149149
})
150150

src/wagtail_personalisation/views.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
from django import forms
44

5-
from django.http import HttpResponseForbidden, HttpResponseRedirect
5+
from django.http import HttpResponseForbidden, HttpResponseRedirect, HttpResponseBadRequest, JsonResponse
66
from django.shortcuts import get_object_or_404, reverse
7+
from django.views.decorators.cache import never_cache
8+
from django.views.decorators.http import require_POST
79
from django.utils.translation import ugettext_lazy as _
810
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
911
from wagtail.contrib.modeladmin.views import IndexView
1012
from wagtail.wagtailcore.models import Page
1113

14+
from wagtail_personalisation.adapters import get_segment_adapter
1215
from wagtail_personalisation.models import PersonalisablePage, Segment
1316

1417

@@ -148,3 +151,36 @@ def copy_page_view(request, page_id, segment_id):
148151
return HttpResponseRedirect(edit_url)
149152

150153
return HttpResponseForbidden()
154+
155+
156+
@never_cache
157+
@require_POST
158+
def visit_page(request):
159+
"""Allows a frontend user to submit a page view and retrieve their current
160+
segments on a site that is behind a cache or CDN.
161+
162+
On each page view, the user must POST to this view the page ID and path
163+
that they are browsing. It will return a JSON-formatted document containing
164+
a list of segments that are currently active for them.
165+
"""
166+
segment_adapter = get_segment_adapter(request)
167+
page_id = request.POST.get('page_id')
168+
path = request.POST.get('path')
169+
170+
if page_id is None or path is None:
171+
return HttpResponseBadRequest()
172+
173+
page = Page.objects.filter(id=page_id).only('id', 'slug', 'live').first()
174+
175+
if page is None or page.live is False:
176+
return HttpResponseBadRequest()
177+
178+
segment_adapter.add_page_visit(page, path=path)
179+
segment_adapter.refresh()
180+
181+
return JsonResponse({
182+
'segments': [
183+
segment['encoded_name']
184+
for segment in segment_adapter.get_segments()
185+
]
186+
})

tests/sandbox/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
from wagtail.wagtailadmin import urls as wagtailadmin_urls
66
from wagtail.wagtailcore import urls as wagtail_urls
77
from wagtail.wagtaildocs import urls as wagtaildocs_urls
8+
from wagtail_personalisation.views import visit_page
89

910
urlpatterns = [
1011
url(r'^django-admin/', include(admin.site.urls)),
1112

1213
url(r'^admin/', include(wagtailadmin_urls)),
1314
url(r'^documents/', include(wagtaildocs_urls)),
1415

16+
url(r'^visit-page/', visit_page),
17+
1518
url(r'', include(wagtail_urls)),
1619
]

tests/unit/test_visit_page_view.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from __future__ import absolute_import, unicode_literals
2+
3+
import pytest
4+
from freezegun import freeze_time
5+
from wagtail_factories import SiteFactory
6+
7+
from tests.factories.rule import DayRuleFactory
8+
from tests.factories.segment import SegmentFactory
9+
10+
11+
@pytest.mark.django_db
12+
class TestVisitPageView(object):
13+
14+
def setup(self):
15+
"""
16+
Sets up a site root to test segmenting
17+
"""
18+
self.site = SiteFactory(is_default_site=True)
19+
20+
def test_counts_visits(self, client):
21+
response = client.post('/visit-page/', {
22+
'page_id': 1,
23+
'path': 'foo',
24+
})
25+
26+
assert response.status_code == 200
27+
assert client.session['visit_count'] == [
28+
{'slug': 'root', 'id': 1, 'path': 'foo', 'count': 1}
29+
]
30+
31+
@freeze_time("2017-01-01")
32+
def test_returns_segments(self, client):
33+
day_only_segment = SegmentFactory(name='Day only')
34+
DayRuleFactory(
35+
sun=True,
36+
segment=day_only_segment)
37+
38+
response = client.post('/visit-page/', {
39+
'page_id': 1,
40+
'path': 'foo',
41+
})
42+
43+
assert response.status_code == 200
44+
assert response.json() == {
45+
'segments': ['day-only']
46+
}
47+
48+
def test_get_request(self, client):
49+
response = client.get('/visit-page/')
50+
51+
assert response.status_code == 405
52+
53+
def test_missing_page_id(self, client):
54+
response = client.post('/visit-page/')
55+
56+
assert response.status_code == 400
57+
58+
def test_missing_path(self, client):
59+
response = client.post('/visit-page/', {
60+
'page_id': 1,
61+
})
62+
63+
assert response.status_code == 400
64+
65+
def test_nonexistent_page(self, client):
66+
response = client.post('/visit-page/', {
67+
'page_id': 9999999,
68+
'path': 'foo',
69+
})
70+
71+
assert response.status_code == 400

0 commit comments

Comments
 (0)