8
This repository has been archived on 2023-05-07. You can view files and clone it, but cannot push or open issues or pull requests.
Files
cavemanon-wagtail-personali…/src/wagtail_personalisation/views.py
2022-11-08 14:47:25 +00:00

238 lines
7.5 KiB
Python

import csv
from django import VERSION as DJANGO_VERSION
from django import forms
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse
if DJANGO_VERSION >= (3, 0):
from django.utils.translation import gettext_lazy as _
else:
from django.utils.translation import ugettext_lazy as _
from wagtail import VERSION as WAGTAIL_VERSION
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from wagtail.contrib.modeladmin.views import DeleteView, IndexView
if WAGTAIL_VERSION >= (3, 0):
from wagtail.models import Page
else:
from wagtail.core.models import Page
from wagtail_personalisation.models import Segment
from wagtail_personalisation.utils import can_delete_pages
class SegmentModelIndexView(IndexView):
"""Placeholder for additional list functionality."""
pass
class SegmentModelDashboardView(IndexView):
"""Additional dashboard functionality."""
def media(self):
return forms.Media(
css={"all": ["css/dashboard.css"]}, js=["js/commons.js", "js/dashboard.js"]
)
def get_template_names(self):
return [
"modeladmin/wagtail_personalisation/segment/dashboard.html",
"modeladmin/index.html",
]
class SegmentModelDeleteView(DeleteView):
def get_affected_page_objects(self):
return Page.objects.filter(
pk__in=(self.instance.get_used_pages().values_list("variant_id", flat=True))
)
def get_template_names(self):
return [
"modeladmin/wagtail_personalisation/segment/delete.html",
"modeladmin/delete.html",
]
def delete_instance(self):
page_variants = self.get_affected_page_objects()
if not can_delete_pages(page_variants, self.request.user):
raise PermissionDenied(
"User has no permission to delete variant page objects."
)
# Deleting page objects triggers deletion of the personalisation
# metadata too because of models.CASCADE.
with transaction.atomic():
for variant in page_variants.iterator():
# Delete each one separately so signals are called.
variant.delete()
super().delete_instance()
def post(self, request, *args, **kwargs):
if not can_delete_pages(self.get_affected_page_objects(), self.request.user):
context = self.get_context_data(
cannot_delete_page_variants_error=True,
)
return self.render_to_response(context)
return super().post(request, *args, **kwargs)
@modeladmin_register
class SegmentModelAdmin(ModelAdmin):
"""The model admin for the Segments administration interface."""
model = Segment
index_view_class = SegmentModelIndexView
dashboard_view_class = SegmentModelDashboardView
delete_view_class = SegmentModelDeleteView
menu_icon = "fa-snowflake-o"
add_to_settings_menu = False
list_display = (
"name",
"persistent",
"match_any",
"status",
"page_count",
"variant_count",
"statistics",
)
index_view_extra_js = ["js/commons.js", "js/index.js"]
index_view_extra_css = ["css/index.css"]
form_view_extra_js = [
"js/commons.js",
"js/form.js",
"js/segment_form_control.js",
"wagtailadmin/js/page-chooser-modal.js",
"wagtailadmin/js/page-chooser.js",
]
form_view_extra_css = ["css/form.css"]
def index_view(self, request):
kwargs = {"model_admin": self}
view_class = self.dashboard_view_class
request.session.setdefault("segment_view", "dashboard")
if request.session["segment_view"] != "dashboard":
view_class = self.index_view_class
return view_class.as_view(**kwargs)(request)
def page_count(self, obj):
return len(obj.get_used_pages())
def variant_count(self, obj):
return len(obj.get_created_variants())
def statistics(self, obj):
return _("{visits} visits in {days} days").format(
visits=obj.visit_count, days=obj.get_active_days()
)
def toggle_segment_view(request):
"""Toggle between the list view and dashboard view.
:param request: The http request
:type request: django.http.HttpRequest
:returns: A redirect to the original page
:rtype: django.http.HttpResponseRedirect
"""
if request.user.has_perm("wagtailadmin.access_admin"):
if request.session["segment_view"] == "dashboard":
request.session["segment_view"] = "list"
elif request.session["segment_view"] != "dashboard":
request.session["segment_view"] = "dashboard"
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
return HttpResponseForbidden()
def toggle(request, segment_id):
"""Toggle the status of the selected segment.
:param request: The http request
:type request: django.http.HttpRequest
:param segment_id: The primary key of the segment
:type segment_id: int
:returns: A redirect to the original page
:rtype: django.http.HttpResponseRedirect
"""
if request.user.has_perm("wagtailadmin.access_admin"):
segment = get_object_or_404(Segment, pk=segment_id)
segment.toggle()
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
return HttpResponseForbidden()
def copy_page_view(request, page_id, segment_id):
"""Copy page with selected segment. If the page for the selected segment
already exists the user will be redirected to that particular page.
:param request: The http request
:type request: django.http.HttpRequest
:param page_id: The primary key of the page
:type segment_id: int
:param segment_id: The primary key of the segment
:type segment_id: int
:returns: A redirect to the new page
:rtype: django.http.HttpResponseRedirect
"""
if request.user.has_perm("wagtailadmin.access_admin"):
segment = get_object_or_404(Segment, pk=segment_id)
page = get_object_or_404(Page, pk=page_id).specific
metadata = page.personalisation_metadata
variant_metadata = metadata.metadata_for_segments([segment])
if variant_metadata.exists():
variant = variant_metadata.first()
else:
variant = metadata.copy_for_segment(segment)
edit_url = reverse("wagtailadmin_pages:edit", args=[variant.id])
return HttpResponseRedirect(edit_url)
return HttpResponseForbidden()
# CSV download views
def segment_user_data(request, segment_id):
if request.user.has_perm("wagtailadmin.access_admin"):
segment = get_object_or_404(Segment, pk=segment_id)
response = HttpResponse(content_type="text/csv; charset=utf-8")
response[
"Content-Disposition"
] = "attachment;filename=segment-%s-users.csv" % str(segment_id)
headers = ["Username"]
for rule in segment.get_rules():
if rule.static:
headers.append(rule.get_column_header())
writer = csv.writer(response)
writer.writerow(headers)
for user in segment.static_users.all():
row = [user.username]
for rule in segment.get_rules():
if rule.static:
row.append(rule.get_user_info_string(user))
writer.writerow(row)
return response
return HttpResponseForbidden()