def view_revision(self, request, **kwargs): # render a page for a popup in an old revision revision_pk = kwargs.pop('revision_pk') language = request.GET.get('language') page_version = PageVersion.objects.get(id=revision_pk) # check if the current user may view the revision # -> if the user may see the page user = get_current_user() if not user_can_view_page(user, page_version.draft): messages.error(request, _('Missing permission to view this page.')) prev = request.META.get('HTTP_REFERER') if prev: return redirect(prev) else: raise Http404 page_absolute_url = page_version.hidden_page.get_draft_url( language=language) context = SekizaiContext({ 'render_page': page_version.hidden_page, 'page_version': page_version, 'is_popup': False, 'request': request, 'page_absolute_url': page_absolute_url }) return render(request, self.view_revision_template, context=context)
def add_logout_button(self, parent): # If current page is not published or has view restrictions user is redirected to the home page: # * published page: no redirect # * unpublished page: redirect to the home page # * published page with login_required: redirect to the home page # * published page with view permissions: redirect to the home page page_is_published = self.page and self.page.is_published( self.current_lang) if page_is_published and not self.page.login_required: anon_can_access = page_permissions.user_can_view_page( user=AnonymousUser(), page=self.page, site=self.current_site, ) else: anon_can_access = False on_success = self.toolbar.REFRESH_PAGE if anon_can_access else '/' # We'll show "Logout Joe Bloggs" if the name fields in auth.User are completed, else "Logout jbloggs". If # anything goes wrong, it'll just be "Logout". user_name = self.get_username() logout_menu_text = _('Logout %s') % user_name if user_name else _( 'Logout') parent.add_ajax_item( logout_menu_text, action=admin_reverse('logout'), active=True, on_success=on_success, method='GET', )
def add_logout_button(self, parent): # If current page is not published or has view restrictions user is redirected to the home page: # * published page: no redirect # * unpublished page: redirect to the home page # * published page with login_required: redirect to the home page # * published page with view permissions: redirect to the home page if (self.page and self.page.is_published(self.current_lang) and not self.page.login_required and page_permissions.user_can_view_page(AnonymousUser(), page=self.page)): on_success = self.toolbar.REFRESH_PAGE else: on_success = '/' # We'll show "Logout Joe Bloggs" if the name fields in auth.User are completed, else "Logout jbloggs". If # anything goes wrong, it'll just be "Logout". user_name = self.get_username() logout_menu_text = _('Logout %s') % user_name if user_name else _('Logout') parent.add_ajax_item( logout_menu_text, action=admin_reverse('logout'), active=True, on_success=on_success, method='GET', )
def inner(request, *args, **kwargs): page = request.current_page if page: if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if not user_can_view_page(request.user, page): return _handle_no_page(request, "$") return func(request, *args, **kwargs)
def inner(request, *args, **kwargs): page = request.current_page if page: if page.login_required and not request.user.is_authenticated(): return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL) if not user_can_view_page(request.user, page): return _handle_no_page(request) return func(request, *args, **kwargs)
def test_visibility_after_move_page(self): superuser = self.get_superuser() user1 = self._create_user("user1", is_staff=True, is_superuser=False) visible = create_page("visible", "nav_playground.html", "en", published=True) visible_child = create_page("visible_child", "nav_playground.html", "en", parent=visible, published=True) invisible_for_user1 = create_page("invisible", "nav_playground.html", "en", published=True) assign_user_to_page(visible, user1, grant_on=ACCESS_PAGE_AND_DESCENDANTS, can_view=True) assign_user_to_page(invisible_for_user1, superuser, grant_on=ACCESS_PAGE_AND_DESCENDANTS, can_view=True) with self.login_user_context(user1): response = self.client.get( visible_child.get_public_object().get_absolute_url()) self.assertEqual(response.status_code, 200) response = self.client.get( invisible_for_user1.get_public_object().get_absolute_url()) self.assertEqual(response.status_code, 404) with self.login_user_context(superuser): move_url = self.get_admin_url(Page, 'move_page', visible_child.pk) response = self.client.post( move_url, { 'id': visible_child.pk, 'position': 0, 'target': invisible_for_user1.pk, }) self.assertEqual(response.status_code, 200) visible_child = visible_child.reload() self.assertEqual(visible_child.parent_page.pk, invisible_for_user1.pk) # Ignore cached_func User = get_user_model() user1 = User.objects.get(pk=user1.pk) self.assertFalse(user_can_view_page(user=user1, page=visible_child))
def check_if_page_is_visible(request, page): user = request.user if page.publisher_is_draft: return False if page.login_required and not user.is_authenticated(): return False page_is_visible = user_can_view_page(user, page) if page_is_visible: # Let the cms handle publication dates page_is_visible = Page.objects.published().filter(pk=page.pk).exists() return page_is_visible
def render_page(request, page, current_language, slug): """ Renders a page """ template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context = {} context['lang'] = current_language context['current_page'] = page context['has_change_permissions'] = user_can_change_page( request.user, page) context['has_view_permissions'] = user_can_view_page(request.user, page) if not context['has_view_permissions']: return _handle_no_page(request) response = TemplateResponse(request, template_name, context) response.add_post_render_callback(set_page_cache) # Add headers for X Frame Options - this really should be changed upon moving to class based views xframe_options = page.get_xframe_options() # xframe_options can be None if there's no xframe information on the page # (eg. a top-level page which has xframe options set to "inherit") if xframe_options == Page.X_FRAME_OPTIONS_INHERIT or xframe_options is None: # This is when we defer to django's own clickjacking handling return response # We want to prevent django setting this in their middlewear response.xframe_options_exempt = True if xframe_options == Page.X_FRAME_OPTIONS_ALLOW: # Do nothing, allowed is no header. return response elif xframe_options == Page.X_FRAME_OPTIONS_SAMEORIGIN: response['X-Frame-Options'] = 'SAMEORIGIN' elif xframe_options == Page.X_FRAME_OPTIONS_DENY: response['X-Frame-Options'] = 'DENY' return response
def render_page(request, page, current_language, slug): """ Renders a page """ template_name = get_template_from_request(request, page, no_current_page=True) # fill the context context = {} context["lang"] = current_language context["current_page"] = page context["has_change_permissions"] = user_can_change_page(request.user, page) context["has_view_permissions"] = user_can_view_page(request.user, page) if not context["has_view_permissions"]: return _handle_no_page(request, slug) response = TemplateResponse(request, template_name, context) response.add_post_render_callback(set_page_cache) # Add headers for X Frame Options - this really should be changed upon moving to class based views xframe_options = page.get_xframe_options() # xframe_options can be None if there's no xframe information on the page # (eg. a top-level page which has xframe options set to "inherit") if xframe_options == Page.X_FRAME_OPTIONS_INHERIT or xframe_options is None: # This is when we defer to django's own clickjacking handling return response # We want to prevent django setting this in their middlewear response.xframe_options_exempt = True if xframe_options == Page.X_FRAME_OPTIONS_ALLOW: # Do nothing, allowed is no header. return response elif xframe_options == Page.X_FRAME_OPTIONS_SAMEORIGIN: response["X-Frame-Options"] = "SAMEORIGIN" elif xframe_options == Page.X_FRAME_OPTIONS_DENY: response["X-Frame-Options"] = "DENY" return response
def assertViewNotAllowed(self, page, user=None): if not user: user = AnonymousUser() self.assertFalse(user_can_view_page(user, page))
def assertViewAllowed(self, page, user): self.assertTrue(user_can_view_page(user, page))
def assertViewNotAllowed(self, page, user): self.assertFalse(user_can_view_page(user, page))
def diff_view(self, request, **kwargs): # view that shows a revision on the left and one on the right # if the right revision has value zero: the current page is used! # -> page id is only necessary in the utter case # if the comparison_pk is zero: the latest version is used # comparison_pk and base_pk are primary keys for *pages*! # also called left_pk left_pk = kwargs.pop('left_pk') # also called right_pk right_pk = kwargs.pop('right_pk') page_pk = kwargs.pop('page_pk') right_page_is_active_page = True language = request.GET.get('language') left = 'page' right = 'page' # get the draft we are talking about page_draft = get_object_or_404(Page, pk=page_pk).get_draft_object() # check if the current user may view the revision # -> if the user may see the page user = get_current_user() if not user_can_view_page(user, page_draft): messages.error(request, _('Missing permission to view this page.')) prev = request.META.get('HTTP_REFERER') if prev: return redirect(prev) else: raise Http404 # the right panel has id=0 # -> use the draft of the page # -> else: fetch the page if int(right_pk) == 0: right_page = page_draft right_page_is_active_page = True else: right = 'pageVersion' right_page = PageVersion.objects.get(pk=right_pk) right_page_is_active_page = False # the left panel has id=0 # -> use the latest PageVersion draft of the page # -> else: fetch the page if int(left_pk) == 0: page_draft_versions = PageVersion.objects.filter(draft=page_draft, active=True, language=language)\ .order_by('-hidden_page__changed_date')[:1] if page_draft_versions.count() > 0: left_page = page_draft_versions.first() left = 'pageVersion' else: messages.info(request, _(u'There are no snapshots for this page')) return self.render_close_frame() else: left = 'pageVersion' left_page = PageVersion.objects.get(pk=left_pk) # list of page's revisions to show as the left sidebar revision_list = PageVersion.objects.filter(draft=page_draft, language=language) # group the revisions by date grouped_revisions = {} for rev in revision_list.iterator(): key = rev.hidden_page.changed_date.strftime("%Y-%m-%d") if key not in grouped_revisions.keys(): grouped_revisions[key] = [] grouped_revisions[key].insert(0, rev) sorted_grouped_revisions = sorted(grouped_revisions.items(), key=lambda i: i[0], reverse=True) # differences between the placeholders if left == 'pageVersion': l_page = left_page.hidden_page else: l_page = left_page if right == 'pageVersion': r_page = right_page.hidden_page else: r_page = right_page diffs = create_placeholder_contents(l_page, r_page, request, language) left_page_absolute_url = left_page.hidden_page.get_draft_url( language=language) context = SekizaiContext({ 'left': left, 'right': right, 'left_page': left_page, 'right_page': right_page, 'is_popup': True, 'page': page_draft.pk, 'active_left_page_version_pk': left_page.pk, 'request': request, 'sorted_grouped_revisions': sorted_grouped_revisions, 'active_language': language, 'all_languages': page_draft.languages.split(','), 'diffs': diffs, 'left_page_absolute_url': left_page_absolute_url, 'right_page_is_active_page': right_page_is_active_page }) return render(request, self.diff_view_template, context=context.flatten())
def get_public_page_with_fallbacks(page, request): """ the plugin should show the published page whenever it exists or the draft page otherwise. On a public content, the draft page should not be shown at all but this is left to the caller. This is inspired by what DjangoCMS does in its main view: https://github.com/django-cms/django-cms/blob/3.8.0/cms/views.py#L37 """ page = page.get_public_object() request_language = translation.get_language_from_request(request, check_path=True) if not page: return None # Check permissions site = get_current_site() if not page_permissions.user_can_view_page(request.user, page, site): return None if request.user.is_staff: user_languages = i18n.get_language_list(site_id=site.pk) else: user_languages = i18n.get_public_languages(site_id=site.pk) # These languages are then filtered out by the user allowed languages available_languages = [ language for language in user_languages if language in list(page.get_published_languages()) ] if request_language not in user_languages: # Language is not allowed # Use the default site language default_language = i18n.get_default_language_for_site(site.pk) fallbacks = i18n.get_fallback_languages(default_language, site_id=site.pk) fallbacks = [default_language] + fallbacks else: fallbacks = i18n.get_fallback_languages(request_language, site_id=site.pk) # Only fallback to languages the user is allowed to see fallback_languages = [ language for language in fallbacks if language != request_language and language in available_languages ] if request_language not in available_languages: if not fallback_languages: # There is no page with the requested language # and there's no configured fallbacks return None if request_language in page.get_languages(): # The page was already published and later unpublished in the current # language. In this case we must not fallback to another language. return None return page
def get_relevant_page_with_fallbacks(context, instance): """ The plugin should show the published page whenever it exists or the draft page otherwise but only in edit mode. This is inspired by what DjangoCMS does in its main view: https://github.com/django-cms/django-cms/blob/3.8.0/cms/views.py#L37 """ request = context["request"] site = get_current_site() # Check permissions if not page_permissions.user_can_view_page(request.user, instance.page, site): return None relevant_page = instance.page.get_public_object() if not relevant_page: if context.get( "current_page") and context["current_page"].publisher_is_draft: return instance.page return None if request.user.is_staff: user_languages = i18n.get_language_list(site_id=site.pk) else: user_languages = i18n.get_public_languages(site_id=site.pk) # These languages are then filtered out by the user allowed languages available_languages = [ language for language in user_languages if language in list(relevant_page.get_published_languages()) ] request_language = translation.get_language_from_request(request, check_path=True) if request_language not in user_languages: # Language is not allowed # Use the default site language default_language = i18n.get_default_language_for_site(site.pk) fallbacks = i18n.get_fallback_languages(default_language, site_id=site.pk) fallbacks = [default_language] + fallbacks else: fallbacks = i18n.get_fallback_languages(request_language, site_id=site.pk) # Only fallback to languages the user is allowed to see fallback_languages = [ language for language in fallbacks if language != request_language and language in available_languages ] if request_language not in available_languages: if not fallback_languages: # There is no page with the requested language # and there's no configured fallbacks return None if request_language in relevant_page.get_languages(): # The page was already published and later unpublished in the current # language. In this case we must not fallback to another language. return None return relevant_page