1# -*- coding: utf-8 -*-
2"""
3Edit Toolbar middleware
4"""
5from django import forms
6from django.contrib.admin.models import LogEntry, ADDITION, CHANGE
7from django.core.exceptions import ValidationError
8from django.urls import resolve
9
10from cms.toolbar.toolbar import CMSToolbar
11from cms.toolbar.utils import get_toolbar_from_request
12from cms.utils.conf import get_cms_setting
13from cms.utils.compat.dj import MiddlewareMixin
14from cms.utils.request_ip_resolvers import get_request_ip_resolver
15
16
17get_request_ip = get_request_ip_resolver()
18
19
20class ToolbarMiddleware(MiddlewareMixin):
21    """
22    Middleware to set up CMS Toolbar.
23    """
24
25    def is_cms_request(self, request):
26        toolbar_hide = get_cms_setting('TOOLBAR_HIDE')
27        internal_ips = get_cms_setting('INTERNAL_IPS')
28
29        if internal_ips:
30            client_ip = get_request_ip(request)
31            try:
32                client_ip = forms.GenericIPAddressField().clean(client_ip)
33            except ValidationError:
34                return False
35            else:
36                if client_ip not in internal_ips:
37                    return False
38
39        if not toolbar_hide:
40            return True
41
42        try:
43            match = resolve(request.path_info)
44        except:
45            return False
46
47        return match.url_name in ('pages-root', 'pages-details-by-slug')
48
49    def process_request(self, request):
50        """
51        If we should show the toolbar for this request, put it on
52        request.toolbar.
53        """
54
55        if not self.is_cms_request(request):
56            return
57
58        edit_on = get_cms_setting('CMS_TOOLBAR_URL__EDIT_ON')
59        edit_off = get_cms_setting('CMS_TOOLBAR_URL__EDIT_OFF')
60        disable = get_cms_setting('CMS_TOOLBAR_URL__DISABLE')
61        anonymous_on = get_cms_setting('TOOLBAR_ANONYMOUS_ON')
62        edit_enabled = edit_on in request.GET and 'preview' not in request.GET
63        edit_disabled = edit_off in request.GET or 'preview' in request.GET
64
65        if disable in request.GET:
66            request.session['cms_toolbar_disabled'] = True
67
68        if edit_enabled:
69            # If we actively enter edit mode, we should show the toolbar in any case
70            request.session['cms_toolbar_disabled'] = False
71
72        toolbar_enabled = not request.session.get('cms_toolbar_disabled', False)
73        can_see_toolbar = request.user.is_staff or (anonymous_on and request.user.is_anonymous)
74        show_toolbar = (toolbar_enabled and can_see_toolbar)
75
76        if edit_enabled and show_toolbar and not request.session.get('cms_edit'):
77            # User has explicitly enabled mode
78            # AND can see the toolbar
79            request.session['cms_edit'] = True
80            request.session['cms_preview'] = False
81
82        if edit_disabled or not show_toolbar and request.session.get('cms_edit'):
83            # User has explicitly disabled the toolbar
84            # OR user has explicitly turned off edit mode
85            # OR user can't see toolbar
86            request.session['cms_edit'] = False
87
88        if 'preview' in request.GET and not request.session.get('cms_preview'):
89            # User has explicitly requested a preview of the live page.
90            request.session['cms_preview'] = True
91
92        if request.user.is_staff:
93            try:
94                request.cms_latest_entry = LogEntry.objects.filter(
95                    user=request.user,
96                    action_flag__in=(ADDITION, CHANGE)
97                ).only('pk').order_by('-pk')[0].pk
98            except IndexError:
99                request.cms_latest_entry = -1
100        request.toolbar = CMSToolbar(request)
101
102    def process_response(self, request, response):
103        if not self.is_cms_request(request):
104            return response
105
106        from django.utils.cache import add_never_cache_headers
107
108        toolbar = get_toolbar_from_request(request)
109
110        if toolbar._cache_disabled:
111            add_never_cache_headers(response)
112
113        if hasattr(request, 'user') and request.user.is_staff and response.status_code != 500:
114            try:
115                if hasattr(request, 'cms_latest_entry'):
116                    pk = LogEntry.objects.filter(
117                        user=request.user,
118                        action_flag__in=(ADDITION, CHANGE)
119                    ).only('pk').order_by('-pk')[0].pk
120
121                    if request.cms_latest_entry != pk:
122                        request.session['cms_log_latest'] = pk
123            # If there were no LogEntries, just don't touch the session.
124            # Note that in the case of a user logging-in as another user,
125            # request may have a cms_latest_entry attribute, but there are no
126            # LogEntries for request.user.
127            except IndexError:
128                pass
129        return response
130