Exemple #1
0
def test_doc_api_for_redirect_to_doc(client, api_settings, root_doc,
                                     redirect_doc, cleared_cacheback_cache):
    """
    Test the document API when we're requesting data for a document that
    redirects to another document.
    """
    url = reverse('api.v1.doc', args=[redirect_doc.locale, redirect_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST, follow=True)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == root_doc.locale
    assert doc_data['slug'] == root_doc.slug
    assert doc_data['id'] == root_doc.id
    assert doc_data['title'] == root_doc.title
    assert doc_data['language'] == root_doc.language
    assert doc_data['hrefLang'] == 'en'
    assert doc_data['absoluteURL'] == root_doc.get_absolute_url()
    assert doc_data['wikiURL'] == absolutify(root_doc.get_absolute_url(),
                                             for_wiki_site=True)
    assert doc_data['translateURL'] == absolutify(reverse(
        'wiki.select_locale',
        args=(root_doc.slug, ),
        locale=root_doc.locale,
    ),
                                                  for_wiki_site=True)
    assert doc_data['bodyHTML'] == root_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == root_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == root_doc.get_toc_html()
    assert doc_data['translations'] == []
    assert doc_data['lastModified'] == '2017-04-14T12:15:00'
Exemple #2
0
def test_doc_api_for_redirect_to_doc(client, root_doc, redirect_doc):
    """
    Test the document API when we're requesting data for a document that
    redirects to another document.
    """
    url = reverse("api.v1.doc", args=[redirect_doc.locale, redirect_doc.slug])
    response = client.get(url, follow=True)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data["documentData"]
    assert data["redirectURL"] is None
    doc_data = data["documentData"]
    assert doc_data["locale"] == root_doc.locale
    assert doc_data["slug"] == root_doc.slug
    assert doc_data["id"] == root_doc.id
    assert doc_data["title"] == root_doc.title
    assert doc_data["language"] == root_doc.language
    assert doc_data["hrefLang"] == "en"
    assert doc_data["absoluteURL"] == root_doc.get_absolute_url()
    assert doc_data["wikiURL"] == absolutify(
        root_doc.get_absolute_url(), for_wiki_site=True
    )
    assert doc_data["translateURL"] == absolutify(
        reverse("wiki.select_locale", args=(root_doc.slug,), locale=root_doc.locale,),
        for_wiki_site=True,
    )
    assert doc_data["bodyHTML"] == root_doc.get_body_html()
    assert doc_data["quickLinksHTML"] == root_doc.get_quick_links_html()
    assert doc_data["tocHTML"] == root_doc.get_toc_html()
    assert doc_data["translations"] == []
    assert doc_data["lastModified"] == "2017-04-14T12:15:00"
Exemple #3
0
def _send_payment_received_email(invoice, locale):
    user = get_user_model().objects.get(stripe_customer_id=invoice.customer)
    subscription_info = retrieve_and_synchronize_subscription_info(user)
    locale = locale or settings.WIKI_DEFAULT_LANGUAGE
    context = {
        "payment_date": datetime.fromtimestamp(invoice.created),
        "next_payment_date": subscription_info["next_payment_at"],
        "invoice_number": invoice.number,
        "cost": invoice.total / 100,
        "credit_card_brand": subscription_info["brand"],
        "manage_subscription_url": absolutify(reverse("payment_management")),
        "faq_url": absolutify(reverse("payments_index")),
        "contact_email": settings.CONTRIBUTION_SUPPORT_EMAIL,
    }
    with translation.override(locale):
        subject = render_email("users/email/payment_received/subject.ltxt",
                               context)
        # Email subject *must not* contain newlines
        subject = "".join(subject.splitlines())
        plain = render_email("users/email/payment_received/plain.ltxt",
                             context)

        send_mail_retrying(
            subject,
            plain,
            settings.DEFAULT_FROM_EMAIL,
            [user.email],
            attachment={
                "name": os.path.basename(urlparse(invoice.invoice_pdf).path),
                "bytes": _download_from_url(invoice.invoice_pdf),
                "mime": "application/pdf",
            },
        )
Exemple #4
0
def test_sitemaps(tmpdir, settings, doc_hierarchy, sitemap_storage,
                  storage_mode):
    """
    Test the build of the sitemaps.
    """
    settings.SITE_URL = "https://example.com"
    settings.MEDIA_ROOT = str(tmpdir.mkdir("media"))
    settings.SITEMAP_USE_S3 = storage_mode == "s3"

    build_sitemaps()

    loc_re = re.compile(r"<loc>(.+)</loc>")
    lastmod_re = re.compile(r"<lastmod>(.+)</lastmod>")

    sitemap_file_path = sitemap_storage.joinpaths("sitemap.xml")

    assert sitemap_storage.exists(sitemap_file_path)
    with sitemap_storage.open(sitemap_file_path, "r") as file:
        actual_index_locs = loc_re.findall(file.read())

    # Check for duplicates.
    assert len(actual_index_locs) == len(set(actual_index_locs))

    expected_index_locs = set()
    for locale, _ in settings.LANGUAGES:
        names = ["sitemap_other.xml"]
        actual_locs, actual_lastmods = [], []
        docs = Document.objects.filter(locale=locale)
        if docs.exists():
            names.append("sitemap.xml")
        for name in names:
            sitemap_path = os.path.join("sitemaps", locale, name)
            expected_index_locs.add(absolutify(sitemap_path))
            sitemap_file_path = sitemap_storage.joinpaths(sitemap_path)
            assert sitemap_storage.exists(sitemap_file_path)
            with sitemap_storage.open(sitemap_file_path, "r") as file:
                sitemap = file.read()
                actual_locs.extend(loc_re.findall(sitemap))
                actual_lastmods.extend(lastmod_re.findall(sitemap))

        # Check for duplicates.
        assert len(actual_locs) == len(set(actual_locs))

        expected_locs, expected_lastmods = set(), set()
        expected_locs.add(absolutify(reverse("home", locale=locale)))
        for doc in docs:
            expected_locs.add(absolutify(doc.get_absolute_url()))
            expected_lastmods.add(doc.modified.strftime("%Y-%m-%d"))

        assert set(actual_locs) == expected_locs
        assert set(actual_lastmods) == expected_lastmods

    assert set(actual_index_locs) == expected_index_locs
Exemple #5
0
def test_doc_api_for_redirect_to_doc(client, api_settings, root_doc,
                                     redirect_doc, cleared_cacheback_cache,
                                     ensure_contributors):
    """
    Test the document API when we're requesting data for a document that
    redirects to another document.
    """
    if ensure_contributors:
        # Pre-populate the cache for the call to document_api_data()
        # made within the view that serves the "api.v1.doc" endpoint.
        DocumentContributorsJob().refresh(root_doc.pk)

    url = reverse('api.v1.doc', args=[redirect_doc.locale, redirect_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST, follow=True)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == root_doc.locale
    assert doc_data['slug'] == root_doc.slug
    assert doc_data['id'] == root_doc.id
    assert doc_data['title'] == root_doc.title
    assert doc_data['language'] == root_doc.language
    assert doc_data['hrefLang'] == 'en'
    assert doc_data['absoluteURL'] == root_doc.get_absolute_url()
    assert doc_data['editURL'] == absolutify(root_doc.get_edit_url(),
                                             for_wiki_site=True)
    assert doc_data['translateURL'] == absolutify(reverse(
        'wiki.select_locale',
        args=(root_doc.slug, ),
        locale=root_doc.locale,
    ),
                                                  for_wiki_site=True)
    assert doc_data['bodyHTML'] == root_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == root_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == root_doc.get_toc_html()
    assert doc_data['translations'] == []
    assert doc_data['contributors'] == (['wiki_user']
                                        if ensure_contributors else [])
    assert doc_data['lastModified'] == '2017-04-14T12:15:00'
    assert doc_data['lastModifiedBy'] == 'wiki_user'

    # Clear the cache for a clean slate when calling document_api_data().
    DocumentContributorsJob().delete(root_doc.pk)

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(root_doc,
                                     ensure_contributors=ensure_contributors)
Exemple #6
0
def test_sitemaps(tmpdir, settings, doc_hierarchy):
    """
    Test the build of the sitemaps.
    """
    settings.SITE_URL = 'https://example.com'
    settings.MEDIA_ROOT = str(tmpdir.mkdir('media'))

    build_sitemaps()

    loc_re = re.compile(r'<loc>(.+)</loc>')
    lastmod_re = re.compile(r'<lastmod>(.+)</lastmod>')

    sitemap_file_path = os.path.join(settings.MEDIA_ROOT, 'sitemap.xml')
    assert os.path.exists(sitemap_file_path)
    with open(sitemap_file_path) as file:
        actual_index_locs = loc_re.findall(file.read())

    # Check for duplicates.
    assert len(actual_index_locs) == len(set(actual_index_locs))

    expected_index_locs = set()
    for locale, _ in settings.LANGUAGES:
        names = ['sitemap_other.xml']
        actual_locs, actual_lastmods = [], []
        docs = Document.objects.filter(locale=locale)
        if docs.exists():
            names.append('sitemap.xml')
        for name in names:
            sitemap_path = os.path.join('sitemaps', locale, name)
            expected_index_locs.add(absolutify(sitemap_path))
            sitemap_file_path = os.path.join(settings.MEDIA_ROOT, sitemap_path)
            assert os.path.exists(sitemap_file_path)
            with open(sitemap_file_path) as file:
                sitemap = file.read()
                actual_locs.extend(loc_re.findall(sitemap))
                actual_lastmods.extend(lastmod_re.findall(sitemap))

        # Check for duplicates.
        assert len(actual_locs) == len(set(actual_locs))

        expected_locs, expected_lastmods = set(), set()
        expected_locs.add(absolutify(reverse('home', locale=locale)))
        for doc in docs:
            expected_locs.add(absolutify(doc.get_absolute_url()))
            expected_lastmods.add(doc.modified.strftime('%Y-%m-%d'))

        assert set(actual_locs) == expected_locs
        assert set(actual_lastmods) == expected_lastmods

    assert set(actual_index_locs) == expected_index_locs
Exemple #7
0
def test_doc_api_for_redirect_to_non_doc(client, api_settings, redirect_to_home,
                                         redirect_to_macros, case):
    """
    Test the document API when we're requesting data for a document that
    redirects to a non-document page (either the home page or another).
    """
    if case == 'redirect-to-home':
        doc = redirect_to_home
        expected_redirect_url = '/en-US/'
    else:
        doc = redirect_to_macros
        expected_redirect_url = absolutify('/en-US/dashboards/macros',
                                           for_wiki_site=True)
    url = reverse('api.v1.doc', args=[doc.locale, doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData'] is None
    assert data['redirectURL'] == expected_redirect_url

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(redirect_url=expected_redirect_url)
Exemple #8
0
def send_payment_received_email(stripe_customer_id, locale, timestamp, invoice_pdf):
    user = get_user_model().objects.get(stripe_customer_id=stripe_customer_id)
    locale = locale or settings.WIKI_DEFAULT_LANGUAGE
    context = {
        "payment_date": datetime.datetime.fromtimestamp(timestamp),
        "manage_subscription_url": absolutify(reverse("recurring_payment_management")),
        "faq_url": absolutify(reverse("payments_index")),
        "contact_email": settings.CONTRIBUTION_SUPPORT_EMAIL,
        "invoice_pdf": invoice_pdf,
    }
    with translation.override(locale):
        subject = render_email("users/email/payment_received/subject.ltxt", context)
        # Email subject *must not* contain newlines
        subject = "".join(subject.splitlines())
        plain = render_email("users/email/payment_received/plain.ltxt", context)
        send_mail_retrying(subject, plain, settings.DEFAULT_FROM_EMAIL, [user.email])
Exemple #9
0
def create_missing_stripe_webhook():
    url_path = reverse("users.stripe_hooks")
    url = (
        "https://" + settings.STRIPE_WEBHOOK_HOSTNAME + url_path
        if settings.STRIPE_WEBHOOK_HOSTNAME
        else absolutify(url_path)
    )

    # From https://stripe.com/docs/api/webhook_endpoints/create
    events = (
        # "Occurs whenever an invoice payment attempt succeeds."
        "invoice.payment_succeeded",
        # "Occurs whenever a customer’s subscription ends."
        # Also, if you go into the Stripe Dashboard, click Billing, Subscriptions,
        # and find a customer and click the "Cancel subscription" button, this
        # triggers.
        "customer.subscription.deleted",
    )

    for webhook in stripe.WebhookEndpoint.list().auto_paging_iter():
        if webhook.url == url and set(events) == set(webhook.enabled_events):
            return

    stripe.WebhookEndpoint.create(
        url=url, enabled_events=events,
    )
Exemple #10
0
def document_api_data(doc=None, ensure_contributors=False, redirect_url=None):
    """
    Returns the JSON data for the document for the document API.
    """
    if doc:
        job = DocumentContributorsJob()
        # If "ensure_contributors" is True, we need the contributors since the
        # result will likely be cached, so we'll set "fetch_on_miss" and wait
        # for the result if it's not already available or stale.
        job.fetch_on_miss = ensure_contributors
        contributors = [c['username'] for c in job.get(doc.pk)]
    else:
        contributors = None

    return {
        'locale':
        doc and doc.locale,
        'slug':
        doc and doc.slug,
        'id':
        doc and doc.id,
        'title':
        doc and doc.title,
        'summary':
        doc and doc.get_summary_html(),
        'language':
        doc and doc.language,
        'absoluteURL':
        doc and doc.get_absolute_url(),
        'redirectURL':
        redirect_url,
        'editURL':
        doc and absolutify(doc.get_edit_url(), for_wiki_site=True),
        'bodyHTML':
        doc and doc.get_body_html(),
        'quickLinksHTML':
        doc and doc.get_quick_links_html(),
        'tocHTML':
        doc and doc.get_toc_html(),
        'parents':
        doc and [{
            'url': d.get_absolute_url(),
            'title': d.title
        } for d in doc.parents],
        'translations':
        doc and [{
            'language': t.language,
            'localizedLanguage': _(settings.LOCALES[t.locale].english),
            'locale': t.locale,
            'url': t.get_absolute_url(),
            'title': t.title
        } for t in doc.get_other_translations(fields=('locale', 'slug',
                                                      'title'))],
        'contributors':
        contributors,
        'lastModified': (doc and doc.current_revision
                         and doc.current_revision.created.isoformat()),
        'lastModifiedBy': (doc and doc.current_revision
                           and str(doc.current_revision.creator))
    }
Exemple #11
0
def test_get_content_based_redirect(root_doc, redirect_doc, redirect_to_self,
                                    redirect_to_home, redirect_to_macros,
                                    case):
    if case == "normal":
        doc = root_doc
        expected = None
    elif case == "redirect":
        doc = redirect_doc
        expected = (
            get_s3_key(root_doc,
                       prefix_with_forward_slash=True,
                       suffix_file_extension=False),
            True,
        )
    elif case == "redirect-to-self":
        doc = redirect_to_self
        expected = None
    elif case == "redirect-to-home":
        doc = redirect_to_home
        expected = ("/en-US/", False)
    else:
        doc = redirect_to_macros
        expected = (absolutify("/en-US/dashboards/macros",
                               for_wiki_site=True), False)
    assert get_content_based_redirect(doc) == expected
Exemple #12
0
def test_doc_api_for_redirect_to_non_doc(client, redirect_to_home,
                                         redirect_to_macros, case):
    """
    Test the document API when we're requesting data for a document that
    redirects to a non-document page (either the home page or another).
    """
    if case == 'redirect-to-home':
        doc = redirect_to_home
        expected_redirect_url = '/en-US/'
    else:
        doc = redirect_to_macros
        expected_redirect_url = absolutify('/en-US/dashboards/macros',
                                           for_wiki_site=True)
    url = reverse('api.v1.doc', args=[doc.locale, doc.slug])
    response = client.get(url)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData'] is None
    assert data['redirectURL'] == expected_redirect_url

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(redirect_url=expected_redirect_url)
Exemple #13
0
def get_content_based_redirect(document):
    """
    Returns None if the document is not a content-based redirect, otherwise a
    tuple pair comprising the redirect URL as well as a boolean value. The
    boolean value will be True if this is a redirect to another document,
    otherwise False. If the document is a redirect to another document or a
    redirect to the homepage, a relative URL will be returned, otherwise it
    will be a full URL to the wiki site.
    """
    redirect_url = document.get_redirect_url()
    if redirect_url and (redirect_url != document.get_absolute_url()):
        redirect_document = document.get_redirect_document(id_only=False)
        if redirect_document:
            # This is a redirect to another document.
            return (get_s3_key(redirect_document,
                               prefix_with_forward_slash=True,
                               suffix_file_extension=False), True)
        # This is a redirect to non-document page. For now, if it's the home
        # page, return a relative path (so we stay on the read-only domain),
        # otherwise return the full URL for the wiki site.
        locale = document.locale
        is_home_page = (redirect_url
                        in ('/', '/' + locale, '/{}/'.format(locale)))
        if is_home_page:
            # Let's return a relative URL to the home page for this locale.
            return ('/{}/'.format(locale), False)
        # Otherwise, let's return a full URL to the Wiki site.
        return (absolutify(redirect_url, for_wiki_site=True), False)
    return None
Exemple #14
0
def test_doc_api(client, trans_doc, cleared_cacheback_cache):
    """On success we get document details in a JSON response."""
    url = reverse('api.v1.doc', args=[trans_doc.locale, trans_doc.slug])
    response = client.get(url)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == trans_doc.locale
    assert doc_data['slug'] == trans_doc.slug
    assert doc_data['id'] == trans_doc.id
    assert doc_data['title'] == trans_doc.title
    assert doc_data['language'] == trans_doc.language
    assert doc_data['hrefLang'] == 'fr'
    assert doc_data['absoluteURL'] == trans_doc.get_absolute_url()
    assert doc_data['wikiURL'] == absolutify(trans_doc.get_absolute_url(),
                                             for_wiki_site=True)
    assert doc_data['translateURL'] is None
    assert doc_data['bodyHTML'] == trans_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == trans_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == trans_doc.get_toc_html()
    assert doc_data['translations'] == [{
        'locale': 'en-US',
        'language': 'English (US)',
        'hrefLang': 'en',
        'localizedLanguage': 'Anglais am\u00e9ricain',
        'title': 'Root Document',
        'url': '/en-US/docs/Root'
    }]
    assert doc_data['lastModified'] == '2017-04-14T12:20:00'
Exemple #15
0
def get_content_based_redirect(document):
    """
    Returns None if the document is not a content-based redirect, otherwise a
    tuple pair comprising the redirect URL as well as a boolean value. The
    boolean value will be True if this is a redirect to another document,
    otherwise False. If the document is a redirect to another document or a
    redirect to the homepage, a relative URL will be returned, otherwise it
    will be a full URL to the wiki site.
    """
    redirect_url = document.get_redirect_url()
    if redirect_url and (redirect_url != document.get_absolute_url()):
        redirect_document = document.get_redirect_document(id_only=False)
        if redirect_document:
            # This is a redirect to another document.
            return (get_s3_key(redirect_document, for_redirect=True), True)
        # This is a redirect to non-document page. For now, if it's the home
        # page, return a relative path (so we stay on the read-only domain),
        # otherwise return the full URL for the wiki site.
        locale = document.locale
        is_home_page = (redirect_url in
                        ('/', '/' + locale, '/{}/'.format(locale)))
        if is_home_page:
            # Let's return a relative URL to the home page for this locale.
            return ('/{}/'.format(locale), False)
        # Otherwise, let's return a full URL to the Wiki site.
        return (absolutify(redirect_url, for_wiki_site=True), False)
    return None
Exemple #16
0
    def handle(self, *args, **options):
        base_url = options['baseurl'] or absolutify('')
        if options['nocache']:
            cache_control = 'no-cache'
        else:
            cache_control = 'max-age=0'
        force = options['force']
        invalidate_cdn_cache = not options['skip_cdn_invalidation']

        if options['all']:
            # Query all documents, excluding those whose `last_rendered_at` is
            # within `min_render_age` or NULL.
            min_render_age = (
                datetime.datetime.now() -
                datetime.timedelta(seconds=options['min_age']))
            docs = Document.objects.filter(
                Q(last_rendered_at__isnull=True) |
                Q(last_rendered_at__lt=min_render_age))
            if options['locale']:
                docs = docs.filter(locale=options['locale'])
            if options['not_locale']:
                docs = docs.exclude(locale=options['not_locale'])
            docs = docs.order_by('-modified')
            docs = docs.values_list('id', flat=True)

            self.chain_render_docs(
                docs,
                cache_control,
                base_url,
                force,
                invalidate_cdn_cache=invalidate_cdn_cache)

        else:
            # Accept page paths from command line, but be liberal
            # in what we accept, eg: /en-US/docs/CSS (full path);
            # /en-US/CSS (no /docs); or even en-US/CSS (no leading slash)
            paths = options['paths']
            if not paths:
                raise CommandError('Need at least one document path to render')

            for path in paths:
                if path.startswith('/'):
                    path = path[1:]
                locale, sep, slug = path.partition('/')
                head, sep, tail = slug.partition('/')
                if head == 'docs':
                    slug = tail
                doc = Document.objects.get(locale=locale, slug=slug)
                log.info('Rendering %s (%s)' % (doc, doc.get_absolute_url()))
                try:
                    render_document(
                        doc.pk, cache_control, base_url, force,
                        invalidate_cdn_cache=invalidate_cdn_cache
                    )
                    log.debug('DONE.')
                except DocumentRenderingInProgress:
                    log.error(
                        'Rendering is already in progress for this document.')
Exemple #17
0
def document_api_data(doc=None, ensure_contributors=False, redirect_url=None):
    """
    Returns the JSON data for the document for the document API.
    """
    if redirect_url:
        return {
            'documentData': None,
            'redirectURL': redirect_url,
        }

    job = DocumentContributorsJob()
    # If "ensure_contributors" is True, we need the contributors since the
    # result will likely be cached, so we'll set "fetch_on_miss" and wait
    # for the result if it's not already available or stale.
    job.fetch_on_miss = ensure_contributors
    contributors = [c['username'] for c in job.get(doc.pk)]

    return {
        'documentData': {
            'locale': doc.locale,
            'slug': doc.slug,
            'id': doc.id,
            'title': doc.title,
            'summary': doc.get_summary_html(),
            'language': doc.language,
            'absoluteURL': doc.get_absolute_url(),
            'editURL': absolutify(doc.get_edit_url(), for_wiki_site=True),
            'bodyHTML': doc.get_body_html(),
            'quickLinksHTML': doc.get_quick_links_html(),
            'tocHTML': doc.get_toc_html(),
            'parents': [
                {
                    'url': d.get_absolute_url(),
                    'title': d.title
                } for d in doc.parents
            ],
            'translations': [
                {
                    'language': t.language,
                    'localizedLanguage': _(settings.LOCALES[t.locale].english),
                    'locale': t.locale,
                    'url': t.get_absolute_url(),
                    'title': t.title
                } for t in doc.get_other_translations(
                    fields=('locale', 'slug', 'title'))
            ],
            'contributors': contributors,
            'lastModified': (doc.current_revision and
                             doc.current_revision.created.isoformat()),
            'lastModifiedBy': (doc.current_revision and
                               str(doc.current_revision.creator))
        },
        'redirectURL': None,
    }
Exemple #18
0
def document_api_data(document):
    translations = document.get_other_translations(fields=('locale', 'slug',
                                                           'title'))

    return {
        'locale':
        document.locale,
        'slug':
        document.slug,
        'id':
        document.id,
        'title':
        document.title,
        'summary':
        document.get_summary_html(),
        'language':
        document.language,
        'absoluteURL':
        document.get_absolute_url(),
        'redirectURL':
        document.get_redirect_url(),
        'editURL':
        absolutify(document.get_edit_url(), for_wiki_site=True),
        'bodyHTML':
        document.get_body_html(),
        'quickLinksHTML':
        document.get_quick_links_html(),
        'tocHTML':
        document.get_toc_html(),
        'parents': [{
            'url': d.get_absolute_url(),
            'title': d.title
        } for d in document.parents],
        'translations': [{
            'language':
            t.language,
            'localizedLanguage':
            _(settings.LOCALES[t.locale].english),
            'locale':
            t.locale,
            'url':
            t.get_absolute_url(),
            'title':
            t.title
        } for t in translations],
        'contributors': [c['username'] for c in document.contributors],
        'lastModified':
        document.current_revision.created.isoformat(),
        'lastModifiedBy': (document.current_revision.creator
                           and str(document.current_revision.creator))
    }
Exemple #19
0
def test_doc_api(client, api_settings, trans_doc, cleared_cacheback_cache,
                 ensure_contributors):
    """On success we get document details in a JSON response."""
    if ensure_contributors:
        # Pre-populate the cache for the call to document_api_data()
        # made within the view that serves the "api.v1.doc" endpoint.
        DocumentContributorsJob().refresh(trans_doc.pk)

    url = reverse('api.v1.doc', args=[trans_doc.locale, trans_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == trans_doc.locale
    assert doc_data['slug'] == trans_doc.slug
    assert doc_data['id'] == trans_doc.id
    assert doc_data['title'] == trans_doc.title
    assert doc_data['language'] == trans_doc.language
    assert doc_data['hrefLang'] == 'fr'
    assert doc_data['absoluteURL'] == trans_doc.get_absolute_url()
    assert doc_data['editURL'] == absolutify(trans_doc.get_edit_url(),
                                             for_wiki_site=True)
    assert doc_data['translateURL'] is None
    assert doc_data['bodyHTML'] == trans_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == trans_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == trans_doc.get_toc_html()
    assert doc_data['translations'] == [{
        'locale': 'en-US',
        'language': 'English (US)',
        'hrefLang': 'en',
        'localizedLanguage': u'Anglais am\u00e9ricain',
        'title': 'Root Document',
        'url': '/en-US/docs/Root'
    }]
    assert doc_data['contributors'] == (['wiki_user']
                                        if ensure_contributors else [])
    assert doc_data['lastModified'] == '2017-04-14T12:20:00'
    assert doc_data['lastModifiedBy'] == 'wiki_user'

    # Clear the cache for a clean slate when calling document_api_data().
    DocumentContributorsJob().delete(trans_doc.pk)

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(trans_doc,
                                     ensure_contributors=ensure_contributors)
Exemple #20
0
def test_doc_api(client, trans_doc):
    """On success we get document details in a JSON response."""
    url = reverse("api.v1.doc", args=[trans_doc.locale, trans_doc.slug])
    response = client.get(url)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data["documentData"]
    assert data["redirectURL"] is None
    doc_data = data["documentData"]
    assert doc_data["locale"] == trans_doc.locale
    assert doc_data["slug"] == trans_doc.slug
    assert doc_data["id"] == trans_doc.id
    assert doc_data["title"] == trans_doc.title
    assert doc_data["language"] == trans_doc.language
    assert doc_data["hrefLang"] == "fr"
    assert doc_data["absoluteURL"] == trans_doc.get_absolute_url()
    assert doc_data["wikiURL"] == absolutify(trans_doc.get_absolute_url(),
                                             for_wiki_site=True)
    assert doc_data["editURL"] == absolutify(
        reverse("wiki.edit", args=(trans_doc.slug, ), locale=trans_doc.locale),
        for_wiki_site=True,
    )
    assert doc_data["translateURL"] is None
    assert doc_data["bodyHTML"] == trans_doc.get_body_html()
    assert doc_data["quickLinksHTML"] == trans_doc.get_quick_links_html()
    assert doc_data["tocHTML"] == trans_doc.get_toc_html()
    assert doc_data["translations"] == [{
        "locale": "en-US",
        "language": "English (US)",
        "hrefLang": "en",
        "localizedLanguage": "Anglais am\u00e9ricain",
        "title": "Root Document",
        "url": "/en-US/docs/Root",
    }]
    assert doc_data["lastModified"] == "2017-04-14T12:20:00"
Exemple #21
0
def create_missing_stripe_webhook():
    url_path = reverse("users.stripe_payment_succeeded_hook")
    url = (
        "https://" + settings.STRIPE_WEBHOOK_HOSTNAME + url_path
        if settings.STRIPE_WEBHOOK_HOSTNAME
        else absolutify(url_path)
    )
    event = "invoice.payment_succeeded"

    for webhook in stripe.WebhookEndpoint.list().auto_paging_iter():
        if webhook.url == url and event in webhook.enabled_events:
            return

    stripe.WebhookEndpoint.create(
        url=url, enabled_events=[event],
    )
Exemple #22
0
def test_doc_api(client, api_settings, trans_doc, cleared_cacheback_cache,
                 ensure_contributors):
    """On success we get document details in a JSON response."""
    if ensure_contributors:
        # Pre-populate the cache for the call to document_api_data()
        # made within the view that serves the "api.v1.doc" endpoint.
        DocumentContributorsJob().refresh(trans_doc.pk)

    url = reverse('api.v1.doc', args=[trans_doc.locale, trans_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == trans_doc.locale
    assert doc_data['slug'] == trans_doc.slug
    assert doc_data['id'] == trans_doc.id
    assert doc_data['title'] == trans_doc.title
    assert doc_data['language'] == trans_doc.language
    assert doc_data['absoluteURL'] == trans_doc.get_absolute_url()
    assert doc_data['editURL'] == absolutify(trans_doc.get_edit_url(),
                                             for_wiki_site=True)
    assert doc_data['bodyHTML'] == trans_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == trans_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == trans_doc.get_toc_html()
    assert doc_data['translations'] == [{
        'locale': 'en-US',
        'language': 'English (US)',
        'localizedLanguage': u'Anglais am\u00e9ricain',
        'title': 'Root Document',
        'url': '/en-US/docs/Root'
    }]
    assert doc_data['contributors'] == (
        ['wiki_user'] if ensure_contributors else [])
    assert doc_data['lastModified'] == '2017-04-14T12:20:00'
    assert doc_data['lastModifiedBy'] == 'wiki_user'

    # Clear the cache for a clean slate when calling document_api_data().
    DocumentContributorsJob().delete(trans_doc.pk)

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(
        trans_doc, ensure_contributors=ensure_contributors)
Exemple #23
0
def test_publish_redirect_to_other(get_s3_bucket_mock, redirect_to_macros):
    """
    Test the publish task for a document that redirects to a URL outside the
    S3 bucket, in this case someting other than the home page.
    """
    log_mock = mock.Mock()
    get_s3_bucket_mock.return_value = s3_bucket_mock = get_mocked_s3_bucket()
    publish([redirect_to_macros.pk], log=log_mock)
    s3_bucket_mock.put_object.assert_called_once_with(
        ACL='public-read',
        Key=get_s3_key(redirect_to_macros),
        Body=json.dumps(
            document_api_data(redirect_url=absolutify(
                '/en-US/dashboards/macros', for_wiki_site=True))),
        ContentType='application/json',
        ContentLanguage=redirect_to_macros.locale)
    log_mock.info.assert_called_once_with('Published S3 Object #1')
Exemple #24
0
def test_doc_api_for_redirect_to_doc(client, api_settings, root_doc,
                                     redirect_doc, cleared_cacheback_cache,
                                     ensure_contributors):
    """
    Test the document API when we're requesting data for a document that
    redirects to another document.
    """
    if ensure_contributors:
        # Pre-populate the cache for the call to document_api_data()
        # made within the view that serves the "api.v1.doc" endpoint.
        DocumentContributorsJob().refresh(root_doc.pk)

    url = reverse('api.v1.doc', args=[redirect_doc.locale, redirect_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST, follow=True)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['documentData']
    assert data['redirectURL'] is None
    doc_data = data['documentData']
    assert doc_data['locale'] == root_doc.locale
    assert doc_data['slug'] == root_doc.slug
    assert doc_data['id'] == root_doc.id
    assert doc_data['title'] == root_doc.title
    assert doc_data['language'] == root_doc.language
    assert doc_data['absoluteURL'] == root_doc.get_absolute_url()
    assert doc_data['editURL'] == absolutify(root_doc.get_edit_url(),
                                             for_wiki_site=True)
    assert doc_data['bodyHTML'] == root_doc.get_body_html()
    assert doc_data['quickLinksHTML'] == root_doc.get_quick_links_html()
    assert doc_data['tocHTML'] == root_doc.get_toc_html()
    assert doc_data['translations'] == []
    assert doc_data['contributors'] == (
        ['wiki_user'] if ensure_contributors else [])
    assert doc_data['lastModified'] == '2017-04-14T12:15:00'
    assert doc_data['lastModifiedBy'] == 'wiki_user'

    # Clear the cache for a clean slate when calling document_api_data().
    DocumentContributorsJob().delete(root_doc.pk)

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(
        root_doc, ensure_contributors=ensure_contributors)
Exemple #25
0
def test_publish_redirect_to_other(get_s3_bucket_mock, redirect_to_macros):
    """
    Test the publish task for a document that redirects to a URL outside the
    S3 bucket, in this case someting other than the home page.
    """
    log_mock = mock.Mock()
    get_s3_bucket_mock.return_value = s3_bucket_mock = get_mocked_s3_bucket()
    publish([redirect_to_macros.pk], log=log_mock)
    s3_bucket_mock.put_object.assert_called_once_with(
        ACL='public-read',
        Key=get_s3_key(redirect_to_macros),
        Body=json.dumps(document_api_data(
            redirect_url=absolutify('/en-US/dashboards/macros',
                                    for_wiki_site=True))),
        ContentType='application/json',
        ContentLanguage=redirect_to_macros.locale
    )
    log_mock.info.assert_called_once_with('Published S3 Object #1')
Exemple #26
0
    def handle(self, *args, **options):
        self.options = options
        self.base_url = options['baseurl'] or absolutify('')
        if self.options['nocache']:
            self.cache_control = 'no-cache'
        else:
            self.cache_control = 'max-age=0'

        if options['all']:
            # Query all documents, excluding those whose `last_rendered_at` is
            # within `min_render_age` or NULL.
            min_render_age = (
                datetime.datetime.now() -
                datetime.timedelta(seconds=self.options['min_age']))
            docs = Document.objects.filter(
                Q(last_rendered_at__isnull=True) |
                Q(last_rendered_at__lt=min_render_age))
            docs = docs.order_by('-modified')
            docs = docs.values_list('id', flat=True)

            self.chain_render_docs(docs)

        else:
            if not len(args) == 1:
                raise CommandError('Need at least one document path to render')
            for path in args:
                # Accept a single page path from command line, but be liberal
                # in what we accept, eg: /en-US/docs/CSS (full path);
                # /en-US/CSS (no /docs); or even en-US/CSS (no leading slash)
                if path.startswith('/'):
                    path = path[1:]
                locale, sep, slug = path.partition('/')
                head, sep, tail = slug.partition('/')
                if head == 'docs':
                    slug = tail
                doc = Document.objects.get(locale=locale, slug=slug)
                log.info(u'Rendering {0!s} ({1!s})'.format(doc, doc.get_absolute_url()))
                try:
                    render_document(doc.pk, self.cache_control, self.base_url,
                                    self.options['force'])
                    log.debug(u'DONE.')
                except DocumentRenderingInProgress:
                    log.error(
                        u'Rendering is already in progress for this document.')
Exemple #27
0
    def handle(self, *args, **options):
        self.options = options
        self.base_url = options['baseurl'] or absolutify('')
        if self.options['nocache']:
            self.cache_control = 'no-cache'
        else:
            self.cache_control = 'max-age=0'

        if options['all']:
            # Query all documents, excluding those whose `last_rendered_at` is
            # within `min_render_age` or NULL.
            min_render_age = (
                datetime.datetime.now() -
                datetime.timedelta(seconds=self.options['min_age']))
            docs = Document.objects.filter(
                Q(last_rendered_at__isnull=True) |
                Q(last_rendered_at__lt=min_render_age))
            docs = docs.order_by('-modified')
            docs = docs.values_list('id', flat=True)

            self.chain_render_docs(docs)

        else:
            if not len(args) == 1:
                raise CommandError('Need at least one document path to render')
            for path in args:
                # Accept a single page path from command line, but be liberal
                # in what we accept, eg: /en-US/docs/CSS (full path);
                # /en-US/CSS (no /docs); or even en-US/CSS (no leading slash)
                if path.startswith('/'):
                    path = path[1:]
                locale, sep, slug = path.partition('/')
                head, sep, tail = slug.partition('/')
                if head == 'docs':
                    slug = tail
                doc = Document.objects.get(locale=locale, slug=slug)
                log.info(u'Rendering %s (%s)' % (doc, doc.get_absolute_url()))
                try:
                    render_document(doc.pk, self.cache_control, self.base_url,
                                    self.options['force'])
                    log.debug(u'DONE.')
                except DocumentRenderingInProgress:
                    log.error(
                        u'Rendering is already in progress for this document.')
Exemple #28
0
def create_sendinblue_unsubscribe_webhook():
    url_path = reverse("api.v1.sendinblue_hooks")
    url = ("https://" + settings.CUSTOM_WEBHOOK_HOSTNAME + url_path
           if settings.CUSTOM_WEBHOOK_HOSTNAME else absolutify(url_path))

    # From https://developers.sendinblue.com/reference#createwebhook
    # "Occurs whenever a user unsubscribes through an email's subscription management link."
    events = ("unsubscribed", )

    response = sendinblue.request("GET",
                                  "webhooks",
                                  params={"type": EMAIL_TYPE})

    no_webhooks_found = response.status_code == 404
    if not response.ok and not no_webhooks_found:
        return [
            Error(
                f"Error getting sendinblue webhooks: {response.status_code}",
                id=SENDINBLUE_API_ERROR,
            )
        ]

    if not no_webhooks_found:
        for webhook in response.json()["webhooks"]:
            if webhook["url"] == url and set(events) == set(webhook["events"]):
                return []

    response = sendinblue.request("POST",
                                  "webhooks",
                                  json={
                                      "url": url,
                                      "events": events,
                                      "type": EMAIL_TYPE
                                  })
    if not response.ok:
        return [
            Error(
                f"Error creating sendinblue webhook: {response.status_code}",
                id=SENDINBLUE_API_ERROR,
            )
        ]

    return []
Exemple #29
0
def test_get_content_based_redirect(root_doc, redirect_doc, redirect_to_self,
                                    redirect_to_home, redirect_to_macros, case):
    if case == 'normal':
        doc = root_doc
        expected = None
    elif case == 'redirect':
        doc = redirect_doc
        expected = (get_s3_key(root_doc, for_redirect=True), True)
    elif case == 'redirect-to-self':
        doc = redirect_to_self
        expected = None
    elif case == 'redirect-to-home':
        doc = redirect_to_home
        expected = ('/en-US/', False)
    else:
        doc = redirect_to_macros
        expected = (
            absolutify('/en-US/dashboards/macros', for_wiki_site=True), False)
    assert get_content_based_redirect(doc) == expected
Exemple #30
0
def test_get_content_based_redirect(root_doc, redirect_doc, redirect_to_self,
                                    redirect_to_home, redirect_to_macros, case):
    if case == 'normal':
        doc = root_doc
        expected = None
    elif case == 'redirect':
        doc = redirect_doc
        expected = (get_s3_key(root_doc, prefix_with_forward_slash=True), True)
    elif case == 'redirect-to-self':
        doc = redirect_to_self
        expected = None
    elif case == 'redirect-to-home':
        doc = redirect_to_home
        expected = ('/en-US/', False)
    else:
        doc = redirect_to_macros
        expected = (
            absolutify('/en-US/dashboards/macros', for_wiki_site=True), False)
    assert get_content_based_redirect(doc) == expected
Exemple #31
0
def test_doc_api(client, api_settings, trans_doc, cleared_cacheback_cache):
    """On success we get document details in a JSON response."""

    # The fetch_on_miss mock and the cleared_cacheback_cache fixture
    # are here to ensure that we don't get an old cached value for
    # the contributors property, and also that we don't use []
    # while a celery job is running.
    url = reverse('api.v1.doc', args=[trans_doc.locale, trans_doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['locale'] == trans_doc.locale
    assert data['slug'] == trans_doc.slug
    assert data['id'] == trans_doc.id
    assert data['title'] == trans_doc.title
    assert data['language'] == trans_doc.language
    assert data['absoluteURL'] == trans_doc.get_absolute_url()
    assert data['redirectURL'] == trans_doc.get_redirect_url()
    assert data['editURL'] == absolutify(trans_doc.get_edit_url(),
                                         for_wiki_site=True)
    assert data['bodyHTML'] == trans_doc.get_body_html()
    assert data['quickLinksHTML'] == trans_doc.get_quick_links_html()
    assert data['tocHTML'] == trans_doc.get_toc_html()
    assert data['translations'] == [{
        'locale': 'en-US',
        'language': 'English (US)',
        'localizedLanguage': u'Anglais am\u00e9ricain',
        'title': 'Root Document',
        'url': '/en-US/docs/Root'
    }]
    assert data['contributors'] == ['wiki_user']
    assert data['lastModified'] == '2017-04-14T12:20:00'
    assert data['lastModifiedBy'] == 'wiki_user'

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    data2 = document_api_data(trans_doc)
    assert data == data2
Exemple #32
0
def test_doc_api_for_redirect_to_non_doc(client, api_settings,
                                         redirect_to_home, redirect_to_macros,
                                         case):
    """
    Test the document API when we're requesting data for a document that
    redirects to a non-document page (either the home page or another).
    """
    if case == 'redirect-to-home':
        doc = redirect_to_home
        expected_redirect_url = '/en-US/'
    else:
        doc = redirect_to_macros
        expected_redirect_url = absolutify('/en-US/dashboards/macros',
                                           for_wiki_site=True)
    url = reverse('api.v1.doc', args=[doc.locale, doc.slug])
    response = client.get(url, HTTP_HOST=api_settings.BETA_HOST)
    assert response.status_code == 200
    assert_no_cache_header(response)

    data = response.json()
    assert data['locale'] is None
    assert data['slug'] is None
    assert data['id'] is None
    assert data['title'] is None
    assert data['language'] is None
    assert data['absoluteURL'] is None
    assert data['redirectURL'] == expected_redirect_url
    assert data['editURL'] is None
    assert data['bodyHTML'] is None
    assert data['quickLinksHTML'] is None
    assert data['tocHTML'] is None
    assert data['translations'] is None
    assert data['contributors'] is None
    assert data['lastModified'] is None
    assert data['lastModifiedBy'] is None

    # Also ensure that we get exactly the same data by calling
    # the document_api_data() function directly
    assert data == document_api_data(redirect_url=expected_redirect_url)
Exemple #33
0
def payments_thank_you_email(username, user_email, recurring=False):
    """Create a notification email for new contributor."""
    message_context = {
        'user_email': user_email,
        'username': username,
        'support_mail_link': 'mailto:' + settings.CONTRIBUTION_SUPPORT_EMAIL + '?Subject=Recurring%20payment%20support',
        'support_mail': settings.CONTRIBUTION_SUPPORT_EMAIL,
        'recurring_payment': recurring,
        'recurring_payment_management': absolutify(reverse('recurring_payment_management')),
    }

    # TODO: Remove when we ship translations, get legal approval
    locale = settings.WIKI_DEFAULT_LANGUAGE
    log.debug('Using the locale %s to send the contribution thank you email', locale)

    with translation.override(locale):
        subject = render_email(
            'payments/email/thank_you/subject.ltxt',
            message_context
        )
        content_plain = render_email(
            'payments/email/thank_you/plain.ltxt',
            message_context
        )
        content_html = render_email(
            'payments/email/thank_you/email.html',
            message_context
        )

        email = EmailMultiAlternatives(
            subject,
            content_plain,
            settings.DEFAULT_FROM_EMAIL,
            [user_email]
        )
        email.attach_alternative(content_html, 'text/html')
        email.send()
Exemple #34
0
def document_api_data(doc=None, redirect_url=None):
    """
    Returns the JSON data for the document for the document API.
    """
    if redirect_url:
        return {
            'documentData': None,
            'redirectURL': redirect_url,
        }

    # The original english slug for this document, for google analytics
    if doc.locale == 'en-US':
        en_slug = doc.slug
    elif doc.parent_id and doc.parent.locale == 'en-US':
        en_slug = doc.parent.slug
    else:
        en_slug = ''

    other_translations = doc.get_other_translations(fields=('locale', 'slug',
                                                            'title', 'parent'))
    available_locales = ({doc.locale} | set(t.locale
                                            for t in other_translations))

    doc_absolute_url = doc.get_absolute_url()
    revision = doc.current_or_latest_revision()
    translation_status = None
    if doc.parent_id and revision and revision.localization_in_progress:
        translation_status = 'outdated' if revision.translation_age >= 10 else 'in-progress'
    return {
        'documentData': {
            'locale':
            doc.locale,
            'slug':
            doc.slug,
            'enSlug':
            en_slug,
            'id':
            doc.id,
            'title':
            doc.title,
            'summary':
            doc.get_summary_html(),
            'language':
            doc.language,
            'hrefLang':
            doc.get_hreflang(available_locales),
            'absoluteURL':
            doc_absolute_url,
            'wikiURL':
            absolutify(doc_absolute_url, for_wiki_site=True),
            'translateURL':
            (absolutify(reverse(
                'wiki.select_locale',
                args=(doc.slug, ),
                locale=doc.locale,
            ),
                        for_wiki_site=True) if doc.is_localizable else None),
            'translationStatus':
            translation_status,
            'bodyHTML':
            doc.get_body_html(),
            'quickLinksHTML':
            doc.get_quick_links_html(),
            'tocHTML':
            doc.get_toc_html(),
            'raw':
            doc.html,
            'parents': [{
                'url': d.get_absolute_url(),
                'title': d.title
            } for d in doc.parents],
            'translations': [{
                'language':
                t.language,
                'hrefLang':
                t.get_hreflang(available_locales),
                'localizedLanguage':
                _(settings.LOCALES[t.locale].english),
                'locale':
                t.locale,
                'url':
                t.get_absolute_url(),
                'title':
                t.title
            } for t in other_translations],
            'lastModified': (doc.current_revision
                             and doc.current_revision.created.isoformat()),
        },
        'redirectURL': None,
    }
Exemple #35
0
def document_api_data(doc=None, ensure_contributors=False, redirect_url=None):
    """
    Returns the JSON data for the document for the document API.
    """
    if redirect_url:
        return {
            'documentData': None,
            'redirectURL': redirect_url,
        }

    job = DocumentContributorsJob()
    # If "ensure_contributors" is True, we need the contributors since the
    # result will likely be cached, so we'll set "fetch_on_miss" and wait
    # for the result if it's not already available or stale.
    job.fetch_on_miss = ensure_contributors
    contributors = [c['username'] for c in job.get(doc.pk)]

    # The original english slug for this document, for google analytics
    if doc.locale == 'en-US':
        en_slug = doc.slug
    elif doc.parent_id and doc.parent.locale == 'en-US':
        en_slug = doc.parent.slug
    else:
        en_slug = ''

    other_translations = doc.get_other_translations(fields=('locale', 'slug',
                                                            'title'))
    available_locales = (set([doc.locale]) | set(t.locale
                                                 for t in other_translations))

    return {
        'documentData': {
            'locale':
            doc.locale,
            'slug':
            doc.slug,
            'enSlug':
            en_slug,
            'id':
            doc.id,
            'title':
            doc.title,
            'summary':
            doc.get_summary_html(),
            'language':
            doc.language,
            'hrefLang':
            doc.get_hreflang(available_locales),
            'absoluteURL':
            doc.get_absolute_url(),
            'editURL':
            absolutify(doc.get_edit_url(), for_wiki_site=True),
            'translateURL':
            (absolutify(reverse(
                'wiki.select_locale',
                args=(doc.slug, ),
                locale=doc.locale,
            ),
                        for_wiki_site=True) if doc.is_localizable else None),
            'bodyHTML':
            doc.get_body_html(),
            'quickLinksHTML':
            doc.get_quick_links_html(),
            'tocHTML':
            doc.get_toc_html(),
            'parents': [{
                'url': d.get_absolute_url(),
                'title': d.title
            } for d in doc.parents],
            'translations': [{
                'language':
                t.language,
                'hrefLang':
                t.get_hreflang(available_locales),
                'localizedLanguage':
                _(settings.LOCALES[t.locale].english),
                'locale':
                t.locale,
                'url':
                t.get_absolute_url(),
                'title':
                t.title
            } for t in other_translations],
            'contributors':
            contributors,
            'lastModified': (doc.current_revision
                             and doc.current_revision.created.isoformat()),
            'lastModifiedBy': (doc.current_revision
                               and str(doc.current_revision.creator))
        },
        'redirectURL': None,
    }
    def handle(self, *args, **options):
        base_url = options["baseurl"] or absolutify("")
        if options["nocache"]:
            cache_control = "no-cache"
        else:
            cache_control = "max-age=0"
        force = options["force"]
        invalidate_cdn_cache = not options["skip_cdn_invalidation"]

        if options["all"]:
            # Query all documents, excluding those whose `last_rendered_at` is
            # within `min_render_age` or NULL.
            min_render_age = datetime.datetime.now() - datetime.timedelta(
                seconds=options["min_age"])
            docs = Document.objects.filter(
                Q(last_rendered_at__isnull=True)
                | Q(last_rendered_at__lt=min_render_age))
            if options["locale"]:
                docs = docs.filter(locale=options["locale"])
            if options["not_locale"]:
                docs = docs.exclude(locale=options["not_locale"])
            if options["slugsearch"]:
                if options["slugsearch"].endswith("*"):
                    docs = docs.exclude(
                        slug__startswith=options["slugsearch"].rstrip("*"))
                elif "*" in options["slugsearch"]:
                    raise NotImplementedError("* can only be on the end")
                else:
                    docs = docs.exclude(slug__contains=options["slugsearch"])
            docs = docs.order_by("-modified")
            docs = docs.values_list("id", flat=True)

            self.chain_render_docs(
                docs,
                cache_control,
                base_url,
                force,
                invalidate_cdn_cache=invalidate_cdn_cache,
            )

        else:
            # Accept page paths from command line, but be liberal
            # in what we accept, eg: /en-US/docs/CSS (full path);
            # /en-US/CSS (no /docs); or even en-US/CSS (no leading slash)
            paths = options["paths"]
            if not paths:
                raise CommandError("Need at least one document path to render")

            for path in paths:
                if path.startswith("/"):
                    path = path[1:]
                locale, sep, slug = path.partition("/")
                head, sep, tail = slug.partition("/")
                if head == "docs":
                    slug = tail
                doc = Document.objects.get(locale=locale, slug=slug)
                log.info(f"Rendering {doc} ({doc.get_absolute_url()})")
                try:
                    render_document(
                        doc.pk,
                        cache_control,
                        base_url,
                        force,
                        invalidate_cdn_cache=invalidate_cdn_cache,
                    )
                    log.debug("DONE.")
                except DocumentRenderingInProgress:
                    log.error(
                        "Rendering is already in progress for this document.")
Exemple #37
0
def document_api_data(doc=None, redirect_url=None):
    """
    Returns the JSON data for the document for the document API.
    """
    if redirect_url:
        return {
            "documentData": None,
            "redirectURL": redirect_url,
        }

    # The original english slug for this document, for google analytics
    if doc.locale == "en-US":
        en_slug = doc.slug
    elif doc.parent_id and doc.parent.locale == "en-US":
        en_slug = doc.parent.slug
    else:
        en_slug = ""

    other_translations = doc.get_other_translations(fields=("locale", "slug",
                                                            "title", "parent"))
    available_locales = {doc.locale} | set(t.locale
                                           for t in other_translations)

    doc_absolute_url = doc.get_absolute_url()
    revision = doc.current_or_latest_revision()
    translation_status = None
    if doc.parent_id and revision and revision.localization_in_progress:
        translation_status = ("outdated" if revision.translation_age >= 10 else
                              "in-progress")
    return {
        "documentData": {
            "locale":
            doc.locale,
            "slug":
            doc.slug,
            "enSlug":
            en_slug,
            "id":
            doc.id,
            "title":
            doc.title,
            "summary":
            doc.get_summary_html(),
            "language":
            doc.language,
            "hrefLang":
            doc.get_hreflang(available_locales),
            "absoluteURL":
            doc_absolute_url,
            "wikiURL":
            absolutify(doc_absolute_url, for_wiki_site=True),
            "editURL":
            absolutify(
                reverse("wiki.edit", args=(doc.slug, ), locale=doc.locale),
                for_wiki_site=True,
            ),
            "translateURL": (absolutify(
                reverse("wiki.select_locale",
                        args=(doc.slug, ),
                        locale=doc.locale),
                for_wiki_site=True,
            ) if doc.is_localizable else None),
            "translationStatus":
            translation_status,
            "bodyHTML":
            doc.get_body_html(),
            "quickLinksHTML":
            doc.get_quick_links_html(),
            "tocHTML":
            doc.get_toc_html(),
            "raw":
            doc.html,
            "parents": [{
                "url": d.get_absolute_url(),
                "title": d.title
            } for d in doc.parents],
            "translations": [{
                "language":
                t.language,
                "hrefLang":
                t.get_hreflang(available_locales),
                "localizedLanguage":
                gettext(settings.LOCALES[t.locale].english),
                "locale":
                t.locale,
                "url":
                t.get_absolute_url(),
                "title":
                t.title,
            } for t in other_translations],
            "lastModified": (doc.current_revision
                             and doc.current_revision.created.isoformat()),
        },
        "redirectURL": None,
    }