from __future__ import absolute_import, unicode_literals import logging from django.conf.urls import include, url from django.db import transaction from django.http import Http404 from django.shortcuts import redirect, render from django.template.defaultfilters import pluralize from django.urls import reverse from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from wagtail.admin import messages from wagtail.admin.site_summary import PagesSummaryItem, SummaryItem from wagtail.admin.views.pages import get_valid_next_url_from_request from wagtail.admin.widgets import Button, ButtonWithDropdownFromHook from wagtail.core import hooks from wagtail.core.models import Page from wagtail_personalisation import admin_urls, models, utils from wagtail_personalisation.adapters import get_segment_adapter logger = logging.getLogger(__name__) @hooks.register('register_admin_urls') def register_admin_urls(): """Adds the administration urls for the personalisation apps.""" return [ url(r'^personalisation/', include( admin_urls, namespace='wagtail_personalisation')), ] @hooks.register('before_serve_page') def set_visit_count(page, request, serve_args, serve_kwargs): """Tests the provided rules to see if the request still belongs to a segment. :param page: The page being served :type page: wagtail.core.models.Page :param request: The http request :type request: django.http.HttpRequest """ adapter = get_segment_adapter(request) adapter.add_page_visit(page) @hooks.register('before_serve_page') def segment_user(page, request, serve_args, serve_kwargs): """Apply a segment to a visitor before serving the page. :param page: The page being served :type page: wagtail.core.models.Page :param request: The http request :type request: django.http.HttpRequest """ adapter = get_segment_adapter(request) adapter.refresh() forced_segment = request.GET.get('segment', None) if request.user.is_superuser and forced_segment is not None: segment = models.Segment.objects.filter(pk=forced_segment).first() if segment: adapter.set_segments([segment]) class UserbarSegmentedLinkItem: def __init__(self, segment): self.segment = segment def render(self, request): return f"""
""" @hooks.register('construct_wagtail_userbar') def add_segment_link_items(request, items): for item in models.Segment.objects.enabled(): items.append(UserbarSegmentedLinkItem(item)) return items @hooks.register('before_serve_page') def serve_variant(page, request, serve_args, serve_kwargs): """Apply a segment to a visitor before serving the page. :param page: The page being served :type page: wagtail.core.models.Page :param request: The http request :type request: django.http.HttpRequest :returns: A variant if one is available for the visitor's segment, otherwise the original page :rtype: wagtail.core.models.Page """ user_segments = [] if not isinstance(page, models.PersonalisablePageMixin): return adapter = get_segment_adapter(request) user_segments = adapter.get_segments() metadata = page.personalisation_metadata # If page is not canonical, don't serve it. if not metadata.is_canonical: raise Http404 if user_segments: # TODO: This is never more then one page? (fix query count) metadata = metadata.metadata_for_segments(user_segments) if metadata: variant = metadata.first().variant.specific return variant.serve(request, *serve_args, **serve_kwargs) @hooks.register('construct_explorer_page_queryset') def dont_show_variant(parent_page, pages, request): return utils.exclude_variants(pages) @hooks.register('register_page_listing_buttons') def page_listing_variant_buttons(page, page_perms, is_parent=False): """Adds page listing buttons to personalisable pages. Shows variants for the page (if any) and a 'Create a new variant' button. """ if not isinstance(page, models.PersonalisablePageMixin): return metadata = page.personalisation_metadata if metadata.is_canonical: yield ButtonWithDropdownFromHook( _('Variants'), hook_name='register_page_listing_variant_buttons', page=page, page_perms=page_perms, is_parent=is_parent, attrs={'target': '_blank', 'title': _('Create or edit a variant')}, priority=100) @hooks.register('register_page_listing_variant_buttons') def page_listing_more_buttons(page, page_perms, is_parent=False): """Adds a 'more' button to personalisable pages allowing users to quickly create a new variant for the selected segment. """ if not isinstance(page, models.PersonalisablePageMixin): return metadata = page.personalisation_metadata for vm in metadata.variants_metadata: yield Button('%s variant' % (vm.segment.name), reverse('wagtailadmin_pages:edit', args=[vm.variant_id]), attrs={"title": _('Edit this variant')}, classes=("icon", "icon-fa-pencil"), priority=0) for segment in metadata.get_unused_segments(): yield Button('%s variant' % (segment.name), reverse('segment:copy_page', args=[page.pk, segment.pk]), attrs={"title": _('Create this variant')}, classes=("icon", "icon-fa-plus"), priority=100) yield Button(_('Create a new segment'), reverse('wagtail_personalisation_segment_modeladmin_create'), attrs={"title": _('Create a new segment')}, classes=("icon", "icon-fa-snowflake-o"), priority=200) class CorrectedPagesSummaryItem(PagesSummaryItem): def get_context(self): # Perform the same check as Wagtail to get the correct count. # Only correct the count when a root page is available to the user. # The `PagesSummaryItem` will return a page count of 0 otherwise. # https://github.com/wagtail/wagtail/blob/5c9ff23e229acabad406c42c4e13cbaea32e6c15/wagtail/admin/site_summary.py#L38 context = super().get_context() root_page = context.get('root_page', None) if root_page: pages = utils.exclude_variants( Page.objects.descendant_of(root_page, inclusive=True)) page_count = pages.count() if root_page.is_root(): page_count -= 1 context['total_pages'] = page_count return context @hooks.register('construct_homepage_summary_items') def add_corrected_pages_summary_panel(request, items): """Replaces the Pages summary panel to hide variants.""" for index, item in enumerate(items): if item.__class__ is PagesSummaryItem: items[index] = CorrectedPagesSummaryItem(request) class SegmentSummaryPanel(SummaryItem): """The segment summary panel showing the total amount of segments on the site and allowing quick access to the Segment dashboard. """ order = 2000 def render(self): segment_count = models.Segment.objects.count() target_url = reverse('wagtail_personalisation_segment_modeladmin_index') title = _("Segments") return mark_safe("""