Beispiel #1
0
def _get_page_by_untyped_arg(page_lookup, request, site_id):
    """
    The `page_lookup` argument can be of any of the following types:
    - Integer: interpreted as `pk` of the desired page
    - String: interpreted as `reverse_id` of the desired page
    - `dict`: a dictionary containing keyword arguments to find the desired page
    (for instance: `{'pk': 1}`)
    - `Page`: you can also pass a Page object directly, in which case there will be no database lookup.
    - `None`: the current page will be used
    """
    if page_lookup is None:
        return request.current_page
    if isinstance(page_lookup, Page):
        if request.current_page and request.current_page.pk == page_lookup.pk:
            return request.current_page
        return page_lookup
    if isinstance(page_lookup, str):
        page_lookup = {'reverse_id': page_lookup}
    elif isinstance(page_lookup, int):
        page_lookup = {'pk': page_lookup}
    elif not isinstance(page_lookup, dict):
        raise TypeError('The page_lookup argument can be either a Dictionary, Integer, Page, or String.')
    site = Site.objects._get_site_by_id(site_id)
    try:
        if 'pk' in page_lookup:
            page = Page.objects.select_related('node').get(**page_lookup)
            if request and use_draft(request):
                if page.publisher_is_draft:
                    return page
                else:
                    return page.publisher_draft
            else:
                if page.publisher_is_draft:
                    return page.publisher_public
                else:
                    return page
        else:
            pages = get_page_queryset(site, draft=use_draft(request))
            return pages.select_related('node').get(**page_lookup)
    except Page.DoesNotExist:
        subject = _('Page not found on %(domain)s') % {'domain': site.domain}
        body = _("A template tag couldn't find the page with lookup arguments `%(page_lookup)s\n`. "
                 "The URL of the request was: http://%(host)s%(path)s") \
               % {'page_lookup': repr(page_lookup), 'host': site.domain, 'path': request.path_info}
        if settings.DEBUG:
            raise Page.DoesNotExist(body)
        else:
            mw = settings.MIDDLEWARE
            if getattr(settings, 'SEND_BROKEN_LINK_EMAILS', False):
                mail_managers(subject, body, fail_silently=True)
            elif 'django.middleware.common.BrokenLinkEmailsMiddleware' in mw:
                middle = BrokenLinkEmailsMiddleware()
                domain = request.get_host()
                path = request.get_full_path()
                referer = force_str(request.META.get('HTTP_REFERER', ''), errors='replace')
                if not middle.is_ignorable_request(request, path, domain, referer):
                    mail_managers(subject, body, fail_silently=True)
            return None
    def get_nodes(self, request):
        site = self.renderer.site
        language = self.renderer.request_language
        pages_qs = get_page_queryset(site).select_related('node')
        visible_pages_for_user = get_visible_nodes(request, pages_qs, site)

        if not visible_pages_for_user:
            return []

        cms_extension = apps.get_app_config(
            'djangocms_versioning').cms_extension
        toolbar = get_toolbar_from_request(request)
        edit_or_preview = toolbar.edit_mode_active or toolbar.preview_mode_active
        menu_nodes = []
        node_id_to_page = {}
        homepage_content = None

        # Depending on the toolbar mode, we need to get the correct version.
        # On edit or preview mode: return DRAFT,
        # if DRAFT does not exists then return PUBLISHED.
        # On public mode: return PUBLISHED.
        if edit_or_preview:
            states = [constants.DRAFT, constants.PUBLISHED]
        else:
            states = [constants.PUBLISHED]

        versionable_item = cms_extension.versionables_by_grouper[Page]
        versioned_page_contents = (
            versionable_item.content_model._base_manager.filter(
                language=language,
                page__in=pages_qs,
                versions__state__in=states,
            ).order_by('page__node__path', 'versions__state').select_related(
                'page', 'page__node').prefetch_related('versions'))
        added_pages = []

        for page_content in versioned_page_contents:
            page = page_content.page

            if page not in visible_pages_for_user:
                # The page is restricted for the user.
                # Therefore we avoid adding it to the menu.
                continue

            version = page_content.versions.all()[0]

            if (page.pk in added_pages and edit_or_preview
                    and version.state == constants.PUBLISHED):
                # Page content is already added. This is the case where you
                # have both draft and published and in edit/preview mode.
                # We give priority to draft which is already sorted by the query.
                # Therefore we ignore the published version.
                continue

            page_tree_node = page.node
            parent_id = node_id_to_page.get(page_tree_node.parent_id)

            if page_tree_node.parent_id and not parent_id:
                # If the parent page is not available,
                # we skip adding the menu node.
                continue

            # Construct the url based on the toolbar mode.
            if edit_or_preview:
                url = get_object_preview_url(page_content)
            else:
                url = page_content.get_absolute_url()

            # Create the new navigation node.
            new_node = CMSVersionedNavigationNode(
                id=page.pk,
                attr=_get_attrs_for_node(self.renderer, page_content),
                title=page_content.menu_title or page_content.title,
                url=url,
                visible=page_content.in_navigation,
            )

            if not homepage_content:
                # Set the home page content.
                homepage_content = page_content if page.is_home else None

            cut_homepage = homepage_content and not homepage_content.in_navigation

            if cut_homepage and parent_id == homepage_content.page.pk:
                # When the homepage is hidden from navigation,
                # we need to cut all its direct children from it.
                new_node.parent_id = None
            else:
                new_node.parent_id = parent_id

            node_id_to_page[page_tree_node.pk] = page.pk
            menu_nodes.append(new_node)
            added_pages.append(page.pk)
        return menu_nodes
Beispiel #3
0
    def get_nodes(self, request):
        from cms.models import Title

        site = self.renderer.site
        lang = self.renderer.request_language
        pages = get_page_queryset(
            site,
            draft=self.renderer.draft_mode_active,
            published=not self.renderer.draft_mode_active,
        )

        if is_valid_site_language(lang, site_id=site.pk):
            _valid_language = True
            _hide_untranslated = hide_untranslated(lang, site.pk)
        else:
            _valid_language = False
            _hide_untranslated = False

        if _valid_language:
            # The request language has been explicitly configured
            # for the current site.
            if _hide_untranslated:
                fallbacks = []
            else:
                fallbacks = get_fallback_languages(lang, site_id=site.pk)
            languages = [lang
                         ] + [_lang for _lang in fallbacks if _lang != lang]
        else:
            # The request language is not configured for the current site.
            # Fallback to all configured public languages for the current site.
            languages = get_public_languages(site.pk)
            fallbacks = languages

        pages = (pages.filter(title_set__language__in=languages).
                 select_related('node').order_by('node__path').distinct())

        if not self.renderer.draft_mode_active:
            # we're dealing with public pages.
            # prefetch the draft versions.
            pages = pages.select_related('publisher_public__node')
        pages = get_visible_nodes(request, pages, site)

        if not pages:
            return []

        try:
            homepage = [page for page in pages if page.is_home][0]
        except IndexError:
            homepage = None

        titles = Title.objects.filter(
            language__in=languages,
            publisher_is_draft=self.renderer.draft_mode_active,
        )

        lookup = Prefetch(
            'title_set',
            to_attr='filtered_translations',
            queryset=titles,
        )
        prefetch_related_objects(pages, lookup)
        # Build the blank title instances only once
        blank_title_cache = {
            language: EmptyTitle(language=language)
            for language in languages
        }

        if lang not in blank_title_cache:
            blank_title_cache[lang] = EmptyTitle(language=lang)

        # Maps a node id to its page id
        node_id_to_page = {}

        def _page_to_node(page):
            # EmptyTitle is used to prevent the cms from trying
            # to find a translation in the database
            page.title_cache = blank_title_cache.copy()

            for trans in page.filtered_translations:
                page.title_cache[trans.language] = trans
            menu_node = get_menu_node_for_page(
                self.renderer,
                page,
                language=lang,
                fallbacks=fallbacks,
            )
            return menu_node

        menu_nodes = []

        for page in pages:
            node = page.node
            parent_id = node_id_to_page.get(node.parent_id)

            if node.parent_id and not parent_id:
                # If the parent page is not available (unpublished, etc..)
                # don't bother creating menu nodes for its descendants.
                continue

            menu_node = _page_to_node(page)
            cut_homepage = homepage and not homepage.in_navigation

            if cut_homepage and parent_id == homepage.pk:
                # When the homepage is hidden from navigation,
                # we need to cut all its direct children from it.
                menu_node.parent_id = None
            else:
                menu_node.parent_id = parent_id
            node_id_to_page[node.pk] = page.pk
            menu_nodes.append(menu_node)
        return menu_nodes