def translate(request, document_slug, document_locale, revision_id=None): """ Create a new translation of a wiki document. * document_slug is for the default locale * translation is to the request locale """ # TODO: Refactor this view into two views? (new, edit) # That might help reduce the headache-inducing branchiness. parent_doc = get_object_or_404(Document, locale=settings.WIKI_DEFAULT_LANGUAGE, slug=document_slug) user = request.user if not revision_id: # HACK: Seems weird, but sticking the translate-to locale in a query # param is the best way to avoid the MindTouch-legacy locale # redirection logic. document_locale = request.GET.get('tolocale', document_locale) # Set a "Discard Changes" page discard_href = '' if settings.WIKI_DEFAULT_LANGUAGE == document_locale: # Don't translate to the default language. return redirect(reverse( 'wiki.edit_document', locale=settings.WIKI_DEFAULT_LANGUAGE, args=[parent_doc.slug])) if not parent_doc.is_localizable: message = _lazy(u'You cannot translate this document.') context = {'message': message} return render(request, 'handlers/400.html', context, status=400) if revision_id: get_object_or_404(Revision, pk=revision_id) based_on_rev = parent_doc.current_or_latest_revision() disclose_description = bool(request.GET.get('opendescription')) try: doc = parent_doc.translations.get(locale=document_locale) slug_dict = split_slug(doc.slug) except Document.DoesNotExist: doc = None disclose_description = True slug_dict = split_slug(document_slug) # Find the "real" parent topic, which is its translation try: parent_topic_translated_doc = ( parent_doc.parent_topic.translations.get( locale=document_locale)) slug_dict = split_slug( parent_topic_translated_doc.slug + '/' + slug_dict['specific']) except: pass user_has_doc_perm = ((not doc) or (doc and doc.allows_editing_by(user))) user_has_rev_perm = ((not doc) or (doc and doc.allows_revision_by(user))) if not user_has_doc_perm and not user_has_rev_perm: # User has no perms, bye. raise PermissionDenied doc_form = rev_form = None if user_has_doc_perm: if doc: # If there's an existing doc, populate form from it. discard_href = doc.get_absolute_url() doc.slug = slug_dict['specific'] doc_initial = document_form_initial(doc) else: # If no existing doc, bring over the original title and slug. discard_href = parent_doc.get_absolute_url() doc_initial = {'title': based_on_rev.title, 'slug': slug_dict['specific']} doc_form = DocumentForm(initial=doc_initial) if user_has_rev_perm: initial = {'based_on': based_on_rev.id, 'comment': '', 'toc_depth': based_on_rev.toc_depth, 'localization_tags': ['inprogress']} content = None if revision_id: content = Revision.objects.get(pk=revision_id).content elif not doc: content = based_on_rev.content if content: initial.update(content=kuma.wiki.content.parse(content) .filterEditorSafety() .serialize()) instance = doc and doc.current_or_latest_revision() rev_form = RevisionForm(instance=instance, initial=initial) if request.method == 'POST': which_form = request.POST.get('form', 'both') doc_form_invalid = False # Grab the posted slug value in case it's invalid posted_slug = request.POST.get('slug', slug_dict['specific']) destination_slug = join_slug(slug_dict['parent_split'], posted_slug) if user_has_doc_perm and which_form in ['doc', 'both']: disclose_description = True post_data = request.POST.copy() post_data.update({'locale': document_locale}) post_data.update({'slug': destination_slug}) doc_form = DocumentForm(post_data, instance=doc) doc_form.instance.locale = document_locale doc_form.instance.parent = parent_doc if which_form == 'both': # Sending a new copy of post so the slug change above # doesn't cause problems during validation rev_form = RevisionValidationForm(request.POST.copy()) rev_form.parent_slug = slug_dict['parent'] # If we are submitting the whole form, we need to check that # the Revision is valid before saving the Document. if doc_form.is_valid() and (which_form == 'doc' or rev_form.is_valid()): rev_form = RevisionForm(post_data) if rev_form.is_valid(): doc = doc_form.save(parent_doc) if which_form == 'doc': url = urlparams(reverse('wiki.edit_document', args=[doc.slug], locale=doc.locale), opendescription=1) return redirect(url) else: doc_form.data['slug'] = posted_slug doc_form_invalid = True else: doc_form.data['slug'] = posted_slug doc_form_invalid = True if doc and user_has_rev_perm and which_form in ['rev', 'both']: post_data = request.POST.copy() if 'slug' not in post_data: post_data['slug'] = posted_slug rev_form = RevisionValidationForm(post_data) rev_form.parent_slug = slug_dict['parent'] rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid() and not doc_form_invalid: # append final slug post_data['slug'] = destination_slug # update the post data with the toc_depth of original post_data['toc_depth'] = based_on_rev.toc_depth rev_form = RevisionForm(post_data) rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid(): parent_id = request.POST.get('parent_id', '') # Attempt to set a parent if parent_id: try: parent_doc = get_object_or_404(Document, id=parent_id) rev_form.instance.document.parent = parent_doc doc.parent = parent_doc rev_form.instance.based_on.document = doc.original except Document.DoesNotExist: pass save_revision_and_notify(rev_form, request, doc) return redirect(doc) if doc: from_id = smart_int(request.GET.get('from'), None) to_id = smart_int(request.GET.get('to'), None) revision_from = get_object_or_none(Revision, pk=from_id, document=doc.parent) revision_to = get_object_or_none(Revision, pk=to_id, document=doc.parent) else: revision_from = revision_to = None parent_split = split_slug(parent_doc.slug) allow_add_attachment = ( Attachment.objects.allow_add_attachment_by(request.user)) attachments = [] if doc and doc.attachments: attachments = attachments_json(doc.attachments) language_mapping = get_language_mapping() language = language_mapping[document_locale.lower()] default_locale = language_mapping[settings.WIKI_DEFAULT_LANGUAGE.lower()] context = { 'parent': parent_doc, 'document': doc, 'document_form': doc_form, 'revision_form': rev_form, 'locale': document_locale, 'default_locale': default_locale, 'language': language, 'based_on': based_on_rev, 'disclose_description': disclose_description, 'discard_href': discard_href, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'attachment_data': attachments, 'attachment_data_json': json.dumps(attachments), 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'specific_slug': parent_split['specific'], 'parent_slug': parent_split['parent'], 'revision_from': revision_from, 'revision_to': revision_to, } return render(request, 'wiki/translate.html', context)
def edit(request, document_slug, document_locale, revision_id=None): """Create a new revision of a wiki document, or edit document metadata.""" doc = get_object_or_404(Document, locale=document_locale, slug=document_slug) user = request.user # If this document has a parent, then the edit is handled by the # translate view. Pass it on. if doc.parent and doc.parent.id != doc.id: return translate(request, doc.parent.slug, doc.locale, revision_id, bypass_process_document_path=True) if revision_id: rev = get_object_or_404(Revision, pk=revision_id, document=doc) else: rev = doc.current_revision or doc.revisions.order_by( '-created', '-id')[0] # Keep hold of the full post slug slug_dict = split_slug(document_slug) # Update the slug, removing the parent path, and # *only* using the last piece. # This is only for the edit form. rev.slug = slug_dict['specific'] section_id = request.GET.get('section', None) if section_id and not request.is_ajax(): return HttpResponse(_("Sections may only be edited inline.")) disclose_description = bool(request.GET.get('opendescription')) doc_form = rev_form = None if doc.allows_revision_by(user): rev_form = RevisionForm(instance=rev, initial={ 'based_on': rev.id, 'current_rev': rev.id, 'comment': '' }, section_id=section_id) if doc.allows_editing_by(user): doc_form = DocumentForm(initial=document_form_initial(doc)) # Need to make check *here* to see if this could have a translation parent show_translation_parent_block = ( (document_locale != settings.WIKI_DEFAULT_LANGUAGE) and (not doc.parent_id)) if request.method == 'GET': if not (rev_form or doc_form): # You can't do anything on this page, so get lost. raise PermissionDenied else: # POST is_iframe_target = request.GET.get('iframe', False) is_raw = request.GET.get('raw', False) need_edit_links = request.GET.get('edit_links', False) parent_id = request.POST.get('parent_id', '') # Attempt to set a parent if show_translation_parent_block and parent_id: try: parent_doc = get_object_or_404(Document, id=parent_id) doc.parent = parent_doc except Document.DoesNotExist: pass # Comparing against localized names for the Save button bothers me, so # I embedded a hidden input: which_form = request.POST.get('form') if which_form == 'doc': if doc.allows_editing_by(user): post_data = request.POST.copy() post_data.update({'locale': document_locale}) doc_form = DocumentForm(post_data, instance=doc) if doc_form.is_valid(): # if must be here for section edits if 'slug' in post_data: post_data['slug'] = join_slug( slug_dict['parent_split'], post_data['slug']) # Get the possibly new slug for the imminent redirection: doc = doc_form.save(None) if is_iframe_target: # TODO: Does this really need to be a template? Just # shoehorning data into a single HTML element. response = HttpResponse(""" <span id="iframe-response" data-status="OK" data-current-revision="%s">OK</span> """ % doc.current_revision.id) response['X-Frame-Options'] = 'SAMEORIGIN' return response return HttpResponseRedirect( urlparams(reverse('wiki.edit_document', args=[doc.slug]), opendescription=1)) disclose_description = True else: raise PermissionDenied elif which_form == 'rev': if not doc.allows_revision_by(user): raise PermissionDenied else: post_data = request.POST.copy() rev_form = RevisionForm(post_data, is_iframe_target=is_iframe_target, section_id=section_id) rev_form.instance.document = doc # for rev_form.clean() # Come up with the original revision to which these changes # would be applied. orig_rev_id = request.POST.get('current_rev', False) if orig_rev_id is False: orig_rev = None else: orig_rev = Revision.objects.get(pk=orig_rev_id) # Get the document's actual current revision. curr_rev = doc.current_revision if not rev_form.is_valid(): # Was there a mid-air collision? if 'current_rev' in rev_form._errors: # Jump out to a function to escape indentation hell return _edit_document_collision( request, orig_rev, curr_rev, is_iframe_target, is_raw, rev_form, doc_form, section_id, rev, doc) if rev_form.is_valid(): save_revision_and_notify(rev_form, request, doc) if is_iframe_target: # TODO: Does this really need to be a template? Just # shoehorning data into a single HTML element. response = HttpResponse(""" <span id="iframe-response" data-status="OK" data-current-revision="%s">OK</span> """ % doc.current_revision.id) response['X-Frame-Options'] = 'SAMEORIGIN' return response if (is_raw and orig_rev is not None and curr_rev.id != orig_rev.id): # If this is the raw view, and there was an original # revision, but the original revision differed from the # current revision at start of editing, we should tell # the client to refresh the page. response = HttpResponse('RESET') response['X-Frame-Options'] = 'SAMEORIGIN' response.status_code = 205 return response if rev_form.instance.is_approved: view = 'wiki.document' else: view = 'wiki.document_revisions' # Construct the redirect URL, adding any needed parameters url = reverse(view, args=[doc.slug], locale=doc.locale) params = {} if is_raw: params['raw'] = 'true' if need_edit_links: # Only need to carry over ?edit_links with ?raw, # because they're on by default in the normal UI params['edit_links'] = 'true' if section_id: # If a section was edited, and we're using the raw # content API, constrain to that section. params['section'] = section_id if params: url = '%s?%s' % (url, urlencode(params)) if not is_raw and section_id: # If a section was edited, jump to the section anchor # if we're not getting raw content. url = '%s#%s' % (url, section_id) return HttpResponseRedirect(url) parent_path = parent_slug = '' if slug_dict['parent']: parent_slug = slug_dict['parent'] if doc.parent_topic_id: parent_doc = Document.objects.get(pk=doc.parent_topic_id) parent_path = parent_doc.get_absolute_url() parent_slug = parent_doc.slug attachments = attachments_json(doc.attachments) allow_add_attachment = (Attachment.objects.allow_add_attachment_by( request.user)) context = { 'revision_form': rev_form, 'document_form': doc_form, 'section_id': section_id, 'disclose_description': disclose_description, 'parent_slug': parent_slug, 'parent_path': parent_path, 'revision': rev, 'document': doc, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'attachment_data': attachments, 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'attachment_data_json': json.dumps(attachments) } return render(request, 'wiki/edit_document.html', context)
def edit(request, document_slug, document_locale, revision_id=None): """Create a new revision of a wiki document, or edit document metadata.""" doc = get_object_or_404(Document, locale=document_locale, slug=document_slug) user = request.user # If this document has a parent, then the edit is handled by the # translate view. Pass it on. if doc.parent and doc.parent.id != doc.id: return translate(request, doc.parent.slug, doc.locale, revision_id, bypass_process_document_path=True) if revision_id: rev = get_object_or_404(Revision, pk=revision_id, document=doc) else: rev = doc.current_revision or doc.revisions.order_by('-created', '-id')[0] # Keep hold of the full post slug slug_dict = split_slug(document_slug) # Update the slug, removing the parent path, and # *only* using the last piece. # This is only for the edit form. rev.slug = slug_dict['specific'] section_id = request.GET.get('section', None) if section_id and not request.is_ajax(): return HttpResponse(_("Sections may only be edited inline.")) disclose_description = bool(request.GET.get('opendescription')) doc_form = rev_form = None if doc.allows_revision_by(user): rev_form = RevisionForm(instance=rev, initial={'based_on': rev.id, 'current_rev': rev.id, 'comment': ''}, section_id=section_id) if doc.allows_editing_by(user): doc_form = DocumentForm(initial=document_form_initial(doc)) # Need to make check *here* to see if this could have a translation parent show_translation_parent_block = ( (document_locale != settings.WIKI_DEFAULT_LANGUAGE) and (not doc.parent_id)) if request.method == 'GET': if not (rev_form or doc_form): # You can't do anything on this page, so get lost. raise PermissionDenied else: # POST is_iframe_target = request.GET.get('iframe', False) is_raw = request.GET.get('raw', False) need_edit_links = request.GET.get('edit_links', False) parent_id = request.POST.get('parent_id', '') # Attempt to set a parent if show_translation_parent_block and parent_id: try: parent_doc = get_object_or_404(Document, id=parent_id) doc.parent = parent_doc except Document.DoesNotExist: pass # Comparing against localized names for the Save button bothers me, so # I embedded a hidden input: which_form = request.POST.get('form') if which_form == 'doc': if doc.allows_editing_by(user): post_data = request.POST.copy() post_data.update({'locale': document_locale}) doc_form = DocumentForm(post_data, instance=doc) if doc_form.is_valid(): # if must be here for section edits if 'slug' in post_data: post_data['slug'] = join_slug( slug_dict['parent_split'], post_data['slug']) # Get the possibly new slug for the imminent redirection: doc = doc_form.save(None) if is_iframe_target: # TODO: Does this really need to be a template? Just # shoehorning data into a single HTML element. response = HttpResponse(""" <span id="iframe-response" data-status="OK" data-current-revision="%s">OK</span> """ % doc.current_revision.id) response['X-Frame-Options'] = 'SAMEORIGIN' return response return HttpResponseRedirect( urlparams(reverse('wiki.edit_document', args=[doc.slug]), opendescription=1)) disclose_description = True else: raise PermissionDenied elif which_form == 'rev': if not doc.allows_revision_by(user): raise PermissionDenied else: post_data = request.POST.copy() rev_form = RevisionForm(post_data, is_iframe_target=is_iframe_target, section_id=section_id) rev_form.instance.document = doc # for rev_form.clean() # Come up with the original revision to which these changes # would be applied. orig_rev_id = request.POST.get('current_rev', False) if orig_rev_id is False: orig_rev = None else: orig_rev = Revision.objects.get(pk=orig_rev_id) # Get the document's actual current revision. curr_rev = doc.current_revision if not rev_form.is_valid(): # Was there a mid-air collision? if 'current_rev' in rev_form._errors: # Jump out to a function to escape indentation hell return _edit_document_collision( request, orig_rev, curr_rev, is_iframe_target, is_raw, rev_form, doc_form, section_id, rev, doc) if rev_form.is_valid(): save_revision_and_notify(rev_form, request, doc) if is_iframe_target: # TODO: Does this really need to be a template? Just # shoehorning data into a single HTML element. response = HttpResponse(""" <span id="iframe-response" data-status="OK" data-current-revision="%s">OK</span> """ % doc.current_revision.id) response['X-Frame-Options'] = 'SAMEORIGIN' return response if (is_raw and orig_rev is not None and curr_rev.id != orig_rev.id): # If this is the raw view, and there was an original # revision, but the original revision differed from the # current revision at start of editing, we should tell # the client to refresh the page. response = HttpResponse('RESET') response['X-Frame-Options'] = 'SAMEORIGIN' response.status_code = 205 return response if rev_form.instance.is_approved: view = 'wiki.document' else: view = 'wiki.document_revisions' # Construct the redirect URL, adding any needed parameters url = reverse(view, args=[doc.slug], locale=doc.locale) params = {} if is_raw: params['raw'] = 'true' if need_edit_links: # Only need to carry over ?edit_links with ?raw, # because they're on by default in the normal UI params['edit_links'] = 'true' if section_id: # If a section was edited, and we're using the raw # content API, constrain to that section. params['section'] = section_id if params: url = '%s?%s' % (url, urlencode(params)) if not is_raw and section_id: # If a section was edited, jump to the section anchor # if we're not getting raw content. url = '%s#%s' % (url, section_id) return HttpResponseRedirect(url) parent_path = parent_slug = '' if slug_dict['parent']: parent_slug = slug_dict['parent'] if doc.parent_topic_id: parent_doc = Document.objects.get(pk=doc.parent_topic_id) parent_path = parent_doc.get_absolute_url() parent_slug = parent_doc.slug attachments = attachments_json(doc.attachments) allow_add_attachment = ( Attachment.objects.allow_add_attachment_by(request.user)) context = { 'revision_form': rev_form, 'document_form': doc_form, 'section_id': section_id, 'disclose_description': disclose_description, 'parent_slug': parent_slug, 'parent_path': parent_path, 'revision': rev, 'document': doc, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'attachment_data': attachments, 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'attachment_data_json': json.dumps(attachments) } return render(request, 'wiki/edit_document.html', context)
def document(request, document_slug, document_locale): """ View a wiki document. """ # PUT requests go to the write API. if request.method == 'PUT': if (not request.authkey and not request.user.is_authenticated()): raise PermissionDenied return _document_PUT(request, document_slug, document_locale) fallback_reason = None slug_dict = split_slug(document_slug) # Is there a document at this slug, in this locale? doc, fallback_reason = _get_doc_and_fallback_reason( document_locale, document_slug) if doc is None: # Possible the document once existed, but is now deleted. # If so, show that it was deleted. deletion_log_entries = DocumentDeletionLog.objects.filter( locale=document_locale, slug=document_slug) if deletion_log_entries.exists(): return _document_deleted(request, deletion_log_entries) # We can throw a 404 immediately if the request type is HEAD. # TODO: take a shortcut if the document was found? if request.method == 'HEAD': raise Http404 # Check if we should fall back to default locale. fallback_doc, fallback_reason, redirect_url = _default_locale_fallback( request, document_slug, document_locale) if fallback_doc is not None: doc = fallback_doc if redirect_url is not None: return redirect(redirect_url) else: # If a Document is not found, we may 404 immediately based on # request parameters. if (any([ request.GET.get(param, None) for param in ('raw', 'include', 'nocreate') ]) or not request.user.is_authenticated()): raise Http404 # The user may be trying to create a child page; if a parent exists # for this document, redirect them to the "Create" page # Otherwise, they could be trying to create a main level doc. create_url = _document_redirect_to_create(document_slug, document_locale, slug_dict) return redirect(create_url) # We found a Document. Now we need to figure out how we're going # to display it. # If we're a redirect, and redirecting hasn't been disabled, redirect. # 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()) if redirect_url and redirect_url != doc.get_absolute_url(): url = urlparams(redirect_url, query_dict=request.GET) # TODO: Re-enable the link in this message after Django >1.5 upgrade # Redirected from <a href="%(url)s?redirect=no">%(url)s</a> messages.add_message( request, messages.WARNING, mark_safe( _(u'Redirected from %(url)s') % {"url": request.build_absolute_uri(doc.get_absolute_url())}), extra_tags='wiki_redirect') return HttpResponsePermanentRedirect(url) # Read some request params to see what we're supposed to do. rendering_params = {} for param in ('raw', 'summary', 'include', 'edit_links'): rendering_params[param] = request.GET.get(param, False) is not False rendering_params['section'] = request.GET.get('section', None) rendering_params['render_raw_fallback'] = False rendering_params['use_rendered'] = kumascript.should_use_rendered( doc, request.GET) # Get us some HTML to play with. doc_html, ks_errors, render_raw_fallback = _get_html_and_errors( request, doc, rendering_params) rendering_params['render_raw_fallback'] = render_raw_fallback toc_html = None # Start parsing and applying filters. if not doc.is_template: if doc.show_toc and not rendering_params['raw']: toc_html = doc.get_toc_html() else: toc_html = None doc_html = _filter_doc_html(request, doc, doc_html, rendering_params) # If we're doing raw view, bail out to that now. if rendering_params['raw']: return _document_raw(request, doc, doc_html, rendering_params) # Get the SEO summary seo_summary = '' if not doc.is_template: seo_summary = doc.get_summary_text() # Get the additional title information, if necessary. seo_parent_title = _get_seo_parent_title(slug_dict, document_locale) # Retrieve file attachments attachments = attachments_json(doc.attachments) # Retrieve pre-parsed content hunks if doc.is_template: quick_links_html, zone_subnav_html = None, None body_html = doc_html else: quick_links_html = doc.get_quick_links_html() zone_subnav_html = doc.get_zone_subnav_html() body_html = doc.get_body_html() share_text = _('I learned about %(title)s on MDN.') % {"title": doc.title} if waffle.flag_is_active(request, 'top_contributors'): contributors = doc.contributors else: contributors = [] contributors_count = len(contributors) has_contributors = contributors_count > 0 # Bundle it all up and, finally, return. context = { 'document': doc, 'document_html': doc_html, 'toc_html': toc_html, 'quick_links_html': quick_links_html, 'zone_subnav_html': zone_subnav_html, 'body_html': body_html, 'contributors': contributors, 'contributors_count': contributors_count, 'contributors_limit': 13, 'has_contributors': has_contributors, 'fallback_reason': fallback_reason, 'kumascript_errors': ks_errors, 'render_raw_fallback': rendering_params['render_raw_fallback'], 'seo_summary': seo_summary, 'seo_parent_title': seo_parent_title, 'share_text': share_text, 'attachment_data': attachments, 'attachment_data_json': json.dumps(attachments), 'search_url': referrer_url(request) or '', } response = render(request, 'wiki/document.html', context) return _set_common_headers(doc, rendering_params['section'], response)
def translate(request, document_slug, document_locale, revision_id=None): """ Create a new translation of a wiki document. * document_slug is for the default locale * translation is to the request locale """ # TODO: Refactor this view into two views? (new, edit) # That might help reduce the headache-inducing branchiness. parent_doc = get_object_or_404(Document, locale=settings.WIKI_DEFAULT_LANGUAGE, slug=document_slug) user = request.user if not revision_id: # HACK: Seems weird, but sticking the translate-to locale in a query # param is the best way to avoid the MindTouch-legacy locale # redirection logic. document_locale = request.GET.get('tolocale', document_locale) # Set a "Discard Changes" page discard_href = '' if settings.WIKI_DEFAULT_LANGUAGE == document_locale: # Don't translate to the default language. return redirect( reverse('wiki.edit_document', locale=settings.WIKI_DEFAULT_LANGUAGE, args=[parent_doc.slug])) if not parent_doc.is_localizable: message = _lazy(u'You cannot translate this document.') context = {'message': message} return render(request, 'handlers/400.html', context, status=400) if revision_id: get_object_or_404(Revision, pk=revision_id) based_on_rev = parent_doc.current_or_latest_revision() disclose_description = bool(request.GET.get('opendescription')) try: doc = parent_doc.translations.get(locale=document_locale) slug_dict = split_slug(doc.slug) except Document.DoesNotExist: doc = None disclose_description = True slug_dict = split_slug(document_slug) # Find the "real" parent topic, which is its translation try: parent_topic_translated_doc = ( parent_doc.parent_topic.translations.get( locale=document_locale)) slug_dict = split_slug(parent_topic_translated_doc.slug + '/' + slug_dict['specific']) except: pass user_has_doc_perm = ((not doc) or (doc and doc.allows_editing_by(user))) user_has_rev_perm = ((not doc) or (doc and doc.allows_revision_by(user))) if not user_has_doc_perm and not user_has_rev_perm: # User has no perms, bye. raise PermissionDenied doc_form = rev_form = None if user_has_doc_perm: if doc: # If there's an existing doc, populate form from it. discard_href = doc.get_absolute_url() doc.slug = slug_dict['specific'] doc_initial = document_form_initial(doc) else: # If no existing doc, bring over the original title and slug. discard_href = parent_doc.get_absolute_url() doc_initial = { 'title': based_on_rev.title, 'slug': slug_dict['specific'] } doc_form = DocumentForm(initial=doc_initial) if user_has_rev_perm: initial = { 'based_on': based_on_rev.id, 'comment': '', 'toc_depth': based_on_rev.toc_depth, 'localization_tags': ['inprogress'] } content = None if revision_id: content = Revision.objects.get(pk=revision_id).content elif not doc: content = based_on_rev.content if content: initial.update(content=kuma.wiki.content.parse( content).filterEditorSafety().serialize()) instance = doc and doc.current_or_latest_revision() rev_form = RevisionForm(instance=instance, initial=initial) if request.method == 'POST': which_form = request.POST.get('form', 'both') doc_form_invalid = False # Grab the posted slug value in case it's invalid posted_slug = request.POST.get('slug', slug_dict['specific']) destination_slug = join_slug(slug_dict['parent_split'], posted_slug) if user_has_doc_perm and which_form in ['doc', 'both']: disclose_description = True post_data = request.POST.copy() post_data.update({'locale': document_locale}) post_data.update({'slug': destination_slug}) doc_form = DocumentForm(post_data, instance=doc) doc_form.instance.locale = document_locale doc_form.instance.parent = parent_doc if which_form == 'both': # Sending a new copy of post so the slug change above # doesn't cause problems during validation rev_form = RevisionValidationForm(request.POST.copy()) rev_form.parent_slug = slug_dict['parent'] # If we are submitting the whole form, we need to check that # the Revision is valid before saving the Document. if doc_form.is_valid() and (which_form == 'doc' or rev_form.is_valid()): rev_form = RevisionForm(post_data) if rev_form.is_valid(): doc = doc_form.save(parent_doc) if which_form == 'doc': url = urlparams(reverse('wiki.edit_document', args=[doc.slug], locale=doc.locale), opendescription=1) return redirect(url) else: doc_form.data['slug'] = posted_slug doc_form_invalid = True else: doc_form.data['slug'] = posted_slug doc_form_invalid = True if doc and user_has_rev_perm and which_form in ['rev', 'both']: post_data = request.POST.copy() if 'slug' not in post_data: post_data['slug'] = posted_slug rev_form = RevisionValidationForm(post_data) rev_form.parent_slug = slug_dict['parent'] rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid() and not doc_form_invalid: # append final slug post_data['slug'] = destination_slug # update the post data with the toc_depth of original post_data['toc_depth'] = based_on_rev.toc_depth rev_form = RevisionForm(post_data) rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid(): parent_id = request.POST.get('parent_id', '') # Attempt to set a parent if parent_id: try: parent_doc = get_object_or_404(Document, id=parent_id) rev_form.instance.document.parent = parent_doc doc.parent = parent_doc rev_form.instance.based_on.document = doc.original except Document.DoesNotExist: pass save_revision_and_notify(rev_form, request, doc) return redirect(doc) if doc: from_id = smart_int(request.GET.get('from'), None) to_id = smart_int(request.GET.get('to'), None) revision_from = get_object_or_none(Revision, pk=from_id, document=doc.parent) revision_to = get_object_or_none(Revision, pk=to_id, document=doc.parent) else: revision_from = revision_to = None parent_split = split_slug(parent_doc.slug) allow_add_attachment = (Attachment.objects.allow_add_attachment_by( request.user)) attachments = [] if doc and doc.attachments: attachments = attachments_json(doc.attachments) language_mapping = get_language_mapping() language = language_mapping[document_locale.lower()] default_locale = language_mapping[settings.WIKI_DEFAULT_LANGUAGE.lower()] context = { 'parent': parent_doc, 'document': doc, 'document_form': doc_form, 'revision_form': rev_form, 'locale': document_locale, 'default_locale': default_locale, 'language': language, 'based_on': based_on_rev, 'disclose_description': disclose_description, 'discard_href': discard_href, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'attachment_data': attachments, 'attachment_data_json': json.dumps(attachments), 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'specific_slug': parent_split['specific'], 'parent_slug': parent_split['parent'], 'revision_from': revision_from, 'revision_to': revision_to, } return render(request, 'wiki/translate.html', context)
def document(request, document_slug, document_locale): """ View a wiki document. """ # PUT requests go to the write API. if request.method == 'PUT': if (not request.authkey and not request.user.is_authenticated()): raise PermissionDenied return _document_PUT(request, document_slug, document_locale) fallback_reason = None slug_dict = split_slug(document_slug) # Is there a document at this slug, in this locale? doc, fallback_reason = _get_doc_and_fallback_reason(document_locale, document_slug) if doc is None: # Possible the document once existed, but is now deleted. # If so, show that it was deleted. deletion_log_entries = DocumentDeletionLog.objects.filter( locale=document_locale, slug=document_slug ) if deletion_log_entries.exists(): return _document_deleted(request, deletion_log_entries) # We can throw a 404 immediately if the request type is HEAD. # TODO: take a shortcut if the document was found? if request.method == 'HEAD': raise Http404 # Check if we should fall back to default locale. fallback_doc, fallback_reason, redirect_url = _default_locale_fallback( request, document_slug, document_locale) if fallback_doc is not None: doc = fallback_doc if redirect_url is not None: return redirect(redirect_url) else: # If a Document is not found, we may 404 immediately based on # request parameters. if (any([request.GET.get(param, None) for param in ('raw', 'include', 'nocreate')]) or not request.user.is_authenticated()): raise Http404 # The user may be trying to create a child page; if a parent exists # for this document, redirect them to the "Create" page # Otherwise, they could be trying to create a main level doc. create_url = _document_redirect_to_create(document_slug, document_locale, slug_dict) return redirect(create_url) # We found a Document. Now we need to figure out how we're going # to display it. # If we're a redirect, and redirecting hasn't been disabled, redirect. # 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()) if redirect_url and redirect_url != doc.get_absolute_url(): url = urlparams(redirect_url, query_dict=request.GET) # TODO: Re-enable the link in this message after Django >1.5 upgrade # Redirected from <a href="%(url)s?redirect=no">%(url)s</a> messages.add_message( request, messages.WARNING, mark_safe(_(u'Redirected from %(url)s') % { "url": request.build_absolute_uri(doc.get_absolute_url()) }), extra_tags='wiki_redirect') return HttpResponsePermanentRedirect(url) # Read some request params to see what we're supposed to do. rendering_params = {} for param in ('raw', 'summary', 'include', 'edit_links'): rendering_params[param] = request.GET.get(param, False) is not False rendering_params['section'] = request.GET.get('section', None) rendering_params['render_raw_fallback'] = False rendering_params['use_rendered'] = kumascript.should_use_rendered(doc, request.GET) # Get us some HTML to play with. doc_html, ks_errors, render_raw_fallback = _get_html_and_errors( request, doc, rendering_params) rendering_params['render_raw_fallback'] = render_raw_fallback toc_html = None # Start parsing and applying filters. if not doc.is_template: if doc.show_toc and not rendering_params['raw']: toc_html = doc.get_toc_html() else: toc_html = None doc_html = _filter_doc_html(request, doc, doc_html, rendering_params) # If we're doing raw view, bail out to that now. if rendering_params['raw']: return _document_raw(request, doc, doc_html, rendering_params) # Get the SEO summary seo_summary = '' if not doc.is_template: seo_summary = doc.get_summary_text() # Get the additional title information, if necessary. seo_parent_title = _get_seo_parent_title(slug_dict, document_locale) # Retrieve file attachments attachments = attachments_json(doc.attachments) # Retrieve pre-parsed content hunks if doc.is_template: quick_links_html, zone_subnav_html = None, None body_html = doc_html else: quick_links_html = doc.get_quick_links_html() zone_subnav_html = doc.get_zone_subnav_html() body_html = doc.get_body_html() share_text = _('I learned about %(title)s on MDN.') % {"title": doc.title} contributors = doc.contributors contributors_count = len(contributors) has_contributors = contributors_count > 0 # Bundle it all up and, finally, return. context = { 'document': doc, 'document_html': doc_html, 'toc_html': toc_html, 'quick_links_html': quick_links_html, 'zone_subnav_html': zone_subnav_html, 'body_html': body_html, 'contributors': contributors, 'contributors_count': contributors_count, 'contributors_limit': 13, 'has_contributors': has_contributors, 'fallback_reason': fallback_reason, 'kumascript_errors': ks_errors, 'render_raw_fallback': rendering_params['render_raw_fallback'], 'seo_summary': seo_summary, 'seo_parent_title': seo_parent_title, 'share_text': share_text, 'attachment_data': attachments, 'attachment_data_json': json.dumps(attachments), 'search_url': referrer_url(request) or '', } response = render(request, 'wiki/document.html', context) return _set_common_headers(doc, rendering_params['section'], response)