def document()

in kitsune/wiki/views.py [0:0]


def document(request, document_slug, document=None):
    """View a wiki document."""

    fallback_reason = None
    full_locale_name = None
    vary_on_accept_language = False

    def maybe_vary_on_accept_language(response):
        """
        Patch the VARY header in the response to include "Accept-Language"
        if the Accept-Language header could vary the response, and return
        the response.
        """
        if vary_on_accept_language:
            patch_vary_headers(response, ["accept-language"])
        return response

    doc = get_visible_document_or_404(
        request.user,
        locale=request.LANGUAGE_CODE,
        slug=document_slug,
        look_for_translation_via_parent=True,
        return_parent_if_no_translation=True,
    )

    if doc.slug != document_slug:
        # We've found the translation at a different slug.
        url = doc.get_absolute_url()
        url = urlparams(url, query_dict=request.GET)
        return HttpResponseRedirect(url)

    if doc.locale != request.LANGUAGE_CODE:
        # The "doc" is the parent document.
        if doc.current_revision:
            # Check for unapproved revisions
            unapproved_translation_exists = Revision.objects.filter(
                is_approved=False,
                document__parent=doc,
                document__locale=request.LANGUAGE_CODE,
            ).exists()
            if unapproved_translation_exists:
                fallback_reason = "translation_not_approved"
            else:
                # There is no translation, so we'll fall back to its approved parent,
                # unless we find an approved translation in a fallback locale.
                fallback_reason = "no_translation"

                # Find and show the defined fallback locale rather than the English
                # version of the document. The fallback locale is defined based on
                # the ACCEPT_LANGUAGE header, site-wide locale mapping and custom
                # fallback locale. The custom fallback locale is defined in the
                # FALLBACK_LOCALES array in kitsune/wiki/config.py. See bug 800880
                # for more details
                fallback_locale, vary_on_accept_language = get_fallback_locale(doc, request)

                # If a fallback locale is defined, show the document in that locale,
                # otherwise continue with the document in the default language.
                if fallback_locale:
                    # If we have a fallback locale, it means we're guaranteed to have
                    # a translation in that locale with approved content.
                    doc = doc.translated_to(fallback_locale)
                    # For showing the fallback locale explanation message to the user
                    fallback_reason = "fallback_locale"
                    full_locale_name = {
                        request.LANGUAGE_CODE: LOCALES[request.LANGUAGE_CODE].native,
                        fallback_locale: LOCALES[fallback_locale].native,
                    }

    if not doc.current_revision:
        # We've got a document, but it has no approved content.
        if doc.parent and doc.parent.current_revision:
            # The "doc" is a translation with no approved content, but its
            # parent has approved content, so let's fall back to its parent.
            fallback_reason = "translation_not_approved"
        else:
            # We can't find any approved content to show.
            fallback_reason = "no_content"

    any_localizable_revision = doc.revisions.filter(
        is_approved=True, is_ready_for_localization=True
    ).exists()
    # Obey explicit redirect pages:
    # Don't redirect on redirect=no (like Wikipedia), so we can link from a
    # redirected-to-page back to a "Redirected from..." link, so you can edit
    # the redirect.
    redirect_url = (
        None if request.GET.get("redirect") == "no" else doc.redirect_url(request.LANGUAGE_CODE)
    )
    if redirect_url:
        url = urlparams(
            redirect_url, query_dict=request.GET, redirectslug=doc.slug, redirectlocale=doc.locale
        )
        return maybe_vary_on_accept_language(HttpResponseRedirect(url))

    # Get "redirected from" doc if we were redirected:
    redirect_slug = request.GET.get("redirectslug")
    redirect_locale = request.GET.get("redirectlocale")
    redirected_from = None
    if redirect_slug and redirect_locale:
        try:
            redirected_from = Document.objects.get_visible(
                request.user, locale=redirect_locale, slug=redirect_slug
            )
        except Document.DoesNotExist:
            pass

    contributors = doc.contributors.all()

    products = doc.get_products()
    if len(products) < 1:
        product = Product.active.filter(visible=True)[0]
    else:
        product = products.first()

    # Set the AAQ context for the widget
    set_aaq_context(request, product, multiple_products=len(products) > 1)

    product_topics = Topic.active.filter(products=product, visible=True)

    # Create serialized versions of the document's associated products and topics
    # to be used within GA as parameters/dimensions.
    ga_products = f"/{'/'.join(products.order_by('slug').values_list('slug', flat=True))}/"
    ga_topics = f"/{'/'.join(doc.get_topics().order_by('slug').values_list('slug', flat=True))}/"
    # Provide the actual locale of the document that will also be used as a GA parameter/dimension.
    ga_article_locale = (
        doc.parent.locale
        if (fallback_reason == "translation_not_approved") and doc.parent
        else doc.locale
    )

    # Switching devices section
    switching_devices_product = switching_devices_topic = switching_devices_subtopics = None
    if doc.is_switching_devices_document:
        # make sure that the article is in the right product and topic
        if (
            not products.filter(slug="firefox").exists()
            or not product_topics.filter(slug=settings.FIREFOX_SWITCHING_DEVICES_TOPIC).exists()
        ):
            raise Http404

        switching_devices_product = Product.active.get(slug="firefox")
        switching_devices_topic = Topic.active.get(
            products=switching_devices_product, slug=settings.FIREFOX_SWITCHING_DEVICES_TOPIC
        )
        switching_devices_subtopics = topics_for(
            request.user, product=switching_devices_product, parent=switching_devices_topic
        )

    if document_slug in COLLAPSIBLE_DOCUMENTS.get(request.LANGUAGE_CODE, []):
        document_css_class = "collapsible"
    else:
        document_css_class = ""

    # Build a set of breadcrumbs, ending with the document's title, and
    # starting with the product, with the topic(s) in between.
    # The breadcrumbs are built backwards, and then reversed.

    # Get document title. If it is like "Title - Subtitle", strip off the subtitle.
    trimmed_title = doc.title.split(" - ")[0].strip()
    breadcrumbs = [(None, trimmed_title)]
    # Get the dominant topic, and all parent topics. Save the topic chosen for
    # picking a product later.
    document_topics = doc.get_topics().order_by("display_order")
    if len(document_topics) > 0:
        topic = document_topics.first()
        breadcrumbs.append((topic.get_absolute_url(product.slug), topic.title))
    breadcrumbs.append((product.get_absolute_url(), product.title))
    # The list above was built backwards, so flip this.
    breadcrumbs.reverse()
    votes = HelpfulVote.objects.filter(revision=doc.current_revision).aggregate(
        total_votes=Count("id"),
        helpful_votes=Count("id", filter=Q(helpful=True)),
    )
    helpful_votes = (
        int((votes["helpful_votes"] / votes["total_votes"]) * 100)
        if votes["total_votes"] > 0
        else 0
    )

    is_first_revision = doc.revisions.filter(is_approved=True).count() == 1

    show_aaq_widget = (
        not (doc.parent and doc.parent.slug == "get-community-support")
        and doc.slug != "get-community-support"
    )

    update_kb_visited(request.session, doc)

    data = {
        "document": doc,
        "is_first_revision": is_first_revision,
        "redirected_from": redirected_from,
        "contributors": contributors,
        "fallback_reason": fallback_reason,
        "helpful_votes": helpful_votes,
        "product_topics": product_topics,
        "product": product,
        "products": products,
        "ga_topics": ga_topics,
        "ga_products": ga_products,
        "ga_article_locale": ga_article_locale,
        "related_products": doc.related_products.exclude(pk=product.pk),
        "show_aaq_widget": show_aaq_widget,
        "breadcrumb_items": breadcrumbs,
        "document_css_class": document_css_class,
        "any_localizable_revision": any_localizable_revision,
        "full_locale_name": full_locale_name,
        "switching_devices_product": switching_devices_product,
        "switching_devices_topic": switching_devices_topic,
        "switching_devices_subtopics": switching_devices_subtopics,
        "product_titles": ", ".join(p.title for p in sorted(products, key=lambda p: p.title)),
    }

    return maybe_vary_on_accept_language(render(request, "wiki/document.html", data))