def create(request): """ Create a new wiki page, which is a document and a revision. """ initial_slug = request.GET.get('slug', '') # TODO: Integrate this into a new exception-handling middleware if not request.user.has_perm('wiki.add_document'): context = { 'reason': 'create-page', 'request_page_url': DEV_DOC_REQUEST_FORM, 'email_address': config.EMAIL_LIST_MDN_ADMINS } return render(request, '403-create-page.html', context=context, status=403) # a fake title based on the initial slug passed via a query parameter initial_title = initial_slug.replace('_', ' ') # in case we want to create a sub page under a different document try: # If a parent ID is provided via GET, confirm it exists initial_parent_id = int(request.GET.get('parent', '')) parent_doc = Document.objects.get(pk=initial_parent_id) parent_slug = parent_doc.slug parent_path = parent_doc.get_absolute_url() except (ValueError, Document.DoesNotExist): initial_parent_id = parent_slug = parent_path = '' # in case we want to create a new page by cloning an existing document try: clone_id = int(request.GET.get('clone', '')) except ValueError: clone_id = None context = { 'attachment_form': AttachmentRevisionForm(), 'parent_path': parent_path, 'parent_slug': parent_slug, } if request.method == 'GET': initial_data = {} initial_html = '' initial_tags = '' initial_toc = Revision.TOC_DEPTH_H4 if clone_id: try: clone_doc = Document.objects.get(pk=clone_id) initial_title = clone_doc.title initial_html = clone_doc.html initial_tags = clone_doc.tags.all() if clone_doc.current_revision: initial_toc = clone_doc.current_revision.toc_depth else: initial_toc = 1 except Document.DoesNotExist: pass if parent_slug: initial_data['parent_topic'] = initial_parent_id if initial_slug: initial_data['title'] = initial_title initial_data['slug'] = initial_slug review_tags = REVIEW_FLAG_TAGS_DEFAULT doc_form = DocumentForm(initial=initial_data, parent_slug=parent_slug) initial = { 'slug': initial_slug, 'title': initial_title, 'content': initial_html, 'review_tags': review_tags, 'tags': initial_tags, 'toc_depth': initial_toc } rev_form = RevisionForm(request=request, initial=initial) context.update({ 'parent_id': initial_parent_id, 'document_form': doc_form, 'revision_form': rev_form, 'initial_tags': initial_tags, }) else: submitted_data = request.POST.copy() posted_slug = submitted_data['slug'] submitted_data['locale'] = request.LANGUAGE_CODE if parent_slug: submitted_data['parent_topic'] = initial_parent_id doc_form = DocumentForm(data=submitted_data, parent_slug=parent_slug) rev_form = RevisionForm(request=request, data=submitted_data, parent_slug=parent_slug) if doc_form.is_valid() and rev_form.is_valid(): doc = doc_form.save(parent=None) rev_form.save(doc) if doc.current_revision.is_approved: view = 'wiki.document' else: view = 'wiki.document_revisions' return redirect(reverse(view, args=[doc.slug])) else: doc_form.data['slug'] = posted_slug context.update({ 'document_form': doc_form, 'revision_form': rev_form, }) return render(request, 'wiki/create.html', context)
def translate(request, document_slug, document_locale): """ 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. # The parent document to translate from parent_doc = get_object_or_404(Document, locale=settings.WIKI_DEFAULT_LANGUAGE, slug=document_slug) # 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', locale=settings.WIKI_DEFAULT_LANGUAGE, args=[parent_doc.slug])) if not parent_doc.is_localizable: message = _(u'You cannot translate this document.') context = {'message': message} return render(request, 'handlers/400.html', context, status=400) 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 if parent_doc.parent_topic: 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 ObjectDoesNotExist: pass user_has_doc_perm = (not doc) or (doc and doc.allows_editing_by(request.user)) doc_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, parent_slug=slug_dict['parent']) initial = { 'based_on': based_on_rev.id, 'current_rev': doc.current_or_latest_revision().id if doc else None, 'comment': '', 'toc_depth': based_on_rev.toc_depth, 'localization_tags': ['inprogress'], } content = None if not doc: content = based_on_rev.content if content: # TODO: There will be no need to "filterEditorSafety" when the code # that calls "clean_content" on Revision.save is deployed to # production, AND the current revisions of all docs have had # their content cleaned with "clean_content". initial.update(content=kuma.wiki.content.parse( content).filterEditorSafety().serialize()) instance = doc and doc.current_or_latest_revision() rev_form = RevisionForm(request=request, instance=instance, initial=initial, parent_slug=slug_dict['parent']) if request.method == 'POST': which_form = request.POST.get('form-type', 'both') doc_form_invalid = False # Grab the posted slug value in case it's invalid posted_slug = request.POST.get('slug', slug_dict['specific']) 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}) doc_form = DocumentForm(post_data, instance=doc, parent_slug=slug_dict['parent']) 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 = RevisionForm(request=request, data=post_data, 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()): doc = doc_form.save(parent=parent_doc) if which_form == 'doc': url = urlparams(doc.get_edit_url(), opendescription=1) return redirect(url) else: doc_form.data['slug'] = posted_slug doc_form_invalid = True if doc and which_form in ['rev', 'both']: post_data = request.POST.copy() if 'slug' not in post_data: post_data['slug'] = posted_slug # update the post data with the toc_depth of original post_data['toc_depth'] = based_on_rev.toc_depth # Pass in the locale for the akistmet "blog_lang". post_data['locale'] = document_locale rev_form = RevisionForm(request=request, data=post_data, parent_slug=slug_dict['parent']) rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid() and not doc_form_invalid: 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 rev_form.save(doc) # If this is an Ajax POST, then return a JsonResponse if request.is_ajax(): data = { 'error': False, 'new_revision_id': rev_form.instance.id, } return JsonResponse(data) # Construct the redirect URL, adding any needed parameters url = doc.get_absolute_url() params = {} # Parameter for the document saved, so that we can delete the cached draft on load params['rev_saved'] = request.POST.get('current_rev', '') url = '%s?%s' % (url, urlencode(params)) return redirect(url) else: # If this is an Ajax POST, then return a JsonResponse with error if request.is_ajax(): if 'current_rev' in rev_form._errors: # Make the error message safe so the '<' and '>' don't # get turned into '<' and '>', respectively rev_form.errors['current_rev'][0] = mark_safe( rev_form.errors['current_rev'][0]) errors = [ rev_form.errors[key][0] for key in rev_form.errors.keys() ] data = { "error": True, "error_message": errors, "new_revision_id": rev_form.instance.id, } return JsonResponse(data=data) 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) 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, 'attachment_form': AttachmentRevisionForm(), '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): """ Create a new revision of a wiki document, or edit document metadata. """ doc = get_object_or_404(Document, locale=document_locale, slug=document_slug) # 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, bypass_process_document_path=True) 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(ugettext("Sections may only be edited inline.")) disclose_description = bool(request.GET.get('opendescription')) doc_form = rev_form = None rev_form = RevisionForm(request=request, instance=rev, initial={'based_on': rev.id, 'current_rev': rev.id, 'comment': ''}, section_id=section_id) if doc.allows_editing_by(request.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_async_submit = request.is_ajax() 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-type') if which_form == 'doc': if doc.allows_editing_by(request.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'] = u'/'.join([slug_dict['parent'], post_data['slug']]) # Get the possibly new slug for the imminent redirection: doc = doc_form.save(parent=None) return redirect(urlparams(doc.get_edit_url(), opendescription=1)) disclose_description = True else: raise PermissionDenied elif which_form == 'rev': post_data = request.POST.copy() rev_form = RevisionForm(request=request, data=post_data, is_async_submit=is_async_submit, 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(): # If this was an Ajax POST, then return a JsonResponse if is_async_submit: # Was there a mid-air collision? if 'current_rev' in rev_form._errors: # Make the error message safe so the '<' and '>' don't # get turned into '<' and '>', respectively rev_form.errors['current_rev'][0] = mark_safe( rev_form.errors['current_rev'][0]) errors = [rev_form.errors[key][0] for key in rev_form.errors.keys()] data = { "error": True, "error_message": errors, "new_revision_id": curr_rev.id, } return JsonResponse(data=data) # Jump out to a function to escape indentation hell return _edit_document_collision( request, orig_rev, curr_rev, is_async_submit, is_raw, rev_form, doc_form, section_id, rev, doc) # Was this an Ajax submission that was marked as spam? if is_async_submit and '__all__' in rev_form._errors: # Return a JsonResponse data = { "error": True, "error_message": mark_safe(rev_form.errors['__all__'][0]), "new_revision_id": curr_rev.id, } return JsonResponse(data=data) if rev_form.is_valid(): rev_form.save(doc) 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 # Is this an Ajax POST? if is_async_submit: # This is the most recent revision id new_rev_id = rev.document.revisions.order_by('-id').first().id data = { "error": False, "new_revision_id": new_rev_id } return JsonResponse(data) 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 # Parameter for the document saved, so that we can delete the cached draft on load params['rev_saved'] = curr_rev.id if curr_rev else '' 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 redirect(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 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, 'attachment_form': AttachmentRevisionForm(), } return render(request, 'wiki/edit.html', context)
def create(request): """ Create a new wiki page, which is a document and a revision. """ initial_slug = request.GET.get("slug", "") # TODO: Integrate this into a new exception-handling middleware if not request.user.has_perm("wiki.add_document"): context = { "reason": "create-page", "request_page_url": DEV_DOC_REQUEST_FORM, "email_address": settings.EMAIL_LIST_MDN_ADMINS, } return render(request, "403-create-page.html", context=context, status=403) # a fake title based on the initial slug passed via a query parameter initial_title = initial_slug.replace("_", " ") # in case we want to create a sub page under a different document try: # If a parent ID is provided via GET, confirm it exists initial_parent_id = int(request.GET.get("parent", "")) parent_doc = Document.objects.get(pk=initial_parent_id) parent_slug = parent_doc.slug parent_path = parent_doc.get_absolute_url() except (ValueError, Document.DoesNotExist): initial_parent_id = parent_slug = parent_path = "" # in case we want to create a new page by cloning an existing document try: clone_id = int(request.GET.get("clone", "")) except ValueError: clone_id = None context = { "attachment_form": AttachmentRevisionForm(), "parent_path": parent_path, "parent_slug": parent_slug, } if request.method == "GET": initial_data = {} initial_html = "" initial_tags = "" initial_toc = Revision.TOC_DEPTH_H4 if clone_id: try: clone_doc = Document.objects.get(pk=clone_id) initial_title = clone_doc.title initial_html = clone_doc.html initial_tags = clone_doc.tags.all() if clone_doc.current_revision: initial_toc = clone_doc.current_revision.toc_depth else: initial_toc = 1 except Document.DoesNotExist: pass if parent_slug: initial_data["parent_topic"] = initial_parent_id if initial_slug: initial_data["title"] = initial_title initial_data["slug"] = initial_slug review_tags = REVIEW_FLAG_TAGS_DEFAULT doc_form = DocumentForm(initial=initial_data, parent_slug=parent_slug) initial = { "slug": initial_slug, "title": initial_title, "content": initial_html, "review_tags": review_tags, "tags": initial_tags, "toc_depth": initial_toc, } rev_form = RevisionForm(request=request, initial=initial) context.update({ "parent_id": initial_parent_id, "document_form": doc_form, "revision_form": rev_form, "initial_tags": initial_tags, }) else: submitted_data = request.POST.copy() posted_slug = submitted_data["slug"] submitted_data["locale"] = request.LANGUAGE_CODE if parent_slug: submitted_data["parent_topic"] = initial_parent_id doc_form = DocumentForm(data=submitted_data, parent_slug=parent_slug) rev_form = RevisionForm(request=request, data=submitted_data, parent_slug=parent_slug) if doc_form.is_valid() and rev_form.is_valid(): doc = doc_form.save(parent=None) rev_form.save(doc) if doc.current_revision.is_approved: view = "wiki.document" else: view = "wiki.document_revisions" return redirect(reverse(view, args=[doc.slug])) else: doc_form.data["slug"] = posted_slug context.update({"document_form": doc_form, "revision_form": rev_form}) return render(request, "wiki/create.html", context)
def create(request): """ Create a new wiki page, which is a document and a revision. """ initial_slug = request.GET.get('slug', '') # Try to head off disallowed Template:* creation, right off the bat if not Document.objects.allows_add_by(request.user, initial_slug): raise PermissionDenied # if the initial slug indicates the creation of a new template is_template = initial_slug.startswith(TEMPLATE_TITLE_PREFIX) # a fake title based on the initial slug passed via a query parameter initial_title = initial_slug.replace('_', ' ') # in case we want to create a sub page under a different document try: # If a parent ID is provided via GET, confirm it exists initial_parent_id = int(request.GET.get('parent', '')) parent_doc = Document.objects.get(pk=initial_parent_id) parent_slug = parent_doc.slug parent_path = parent_doc.get_absolute_url() except (ValueError, Document.DoesNotExist): initial_parent_id = parent_slug = parent_path = '' # in case we want to create a new page by cloning an existing document try: clone_id = int(request.GET.get('clone', '')) except ValueError: clone_id = None context = { 'is_template': is_template, 'attachment_form': AttachmentRevisionForm(), 'parent_path': parent_path, 'parent_slug': parent_slug, } if request.method == 'GET': initial_data = {} initial_html = '' initial_tags = '' initial_toc = Revision.TOC_DEPTH_H4 if clone_id: try: clone_doc = Document.objects.get(pk=clone_id) initial_title = clone_doc.title initial_html = clone_doc.html initial_tags = clone_doc.tags.all() if clone_doc.current_revision: initial_toc = clone_doc.current_revision.toc_depth else: initial_toc = 1 except Document.DoesNotExist: pass if parent_slug: initial_data['parent_topic'] = initial_parent_id if initial_slug: initial_data['title'] = initial_title initial_data['slug'] = initial_slug if is_template: review_tags = ('template',) else: review_tags = REVIEW_FLAG_TAGS_DEFAULT doc_form = DocumentForm(initial=initial_data, parent_slug=parent_slug) rev_form = RevisionForm(initial={ 'slug': initial_slug, 'title': initial_title, 'content': initial_html, 'review_tags': review_tags, 'tags': initial_tags, 'toc_depth': initial_toc }) context.update({ 'parent_id': initial_parent_id, 'document_form': doc_form, 'revision_form': rev_form, 'initial_tags': initial_tags, }) else: submitted_data = request.POST.copy() posted_slug = submitted_data['slug'] submitted_data['locale'] = request.locale if parent_slug: submitted_data['parent_topic'] = initial_parent_id doc_form = DocumentForm(submitted_data, parent_slug=parent_slug) rev_form = RevisionForm(data=submitted_data, parent_slug=parent_slug) if doc_form.is_valid() and rev_form.is_valid(): slug = doc_form.cleaned_data['slug'] if not Document.objects.allows_add_by(request.user, slug): raise PermissionDenied doc = doc_form.save(parent=None) rev_form.save(request, doc) if doc.current_revision.is_approved: view = 'wiki.document' else: view = 'wiki.document_revisions' return redirect(reverse(view, args=[doc.slug])) else: doc_form.data['slug'] = posted_slug context.update({ 'document_form': doc_form, 'revision_form': rev_form, }) return render(request, 'wiki/create.html', context)
def translate(request, document_slug, document_locale): """ 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. # The parent document to translate from try: # Use '.all_objects' because the parent might have been soft deleted. # And if we don't respect that fact, it would become impossible to # edit a the child of it. parent_doc = Document.all_objects.get( locale=settings.WIKI_DEFAULT_LANGUAGE, slug=document_slug ) except Document.DoesNotExist: raise Http404("Parent document does not exist") # Get the mapping here and now so it can be used for input validation language_mapping = get_language_mapping() # 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) if document_locale.lower() not in language_mapping: # The 'tolocale' query string parameters aren't free-text. They're # explicitly listed on the "Select language" page (`...$locales`) # If a locale was entered that wasn't a link it's a user bug. raise Http404 # 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", locale=settings.WIKI_DEFAULT_LANGUAGE, args=[parent_doc.slug], ) ) if not parent_doc.is_localizable: message = _("You cannot translate this document.") context = {"message": message} return render(request, "handlers/400.html", context, status=400) 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 if parent_doc.parent_topic: 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 ObjectDoesNotExist: pass user_has_doc_perm = (not doc) or (doc and doc.allows_editing_by(request.user)) doc_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, parent_slug=slug_dict["parent"]) initial = { "based_on": based_on_rev.id, "current_rev": doc.current_or_latest_revision().id if doc else None, "comment": "", "toc_depth": based_on_rev.toc_depth, "localization_tags": ["inprogress"], } content = None if not doc: content = based_on_rev.content if content: # TODO: There will be no need to "filterEditorSafety" when the code # that calls "clean_content" on Revision.save is deployed to # production, AND the current revisions of all docs have had # their content cleaned with "clean_content". initial.update( content=kuma.wiki.content.parse(content).filterEditorSafety().serialize() ) instance = doc and doc.current_or_latest_revision() rev_form = RevisionForm( request=request, instance=instance, initial=initial, parent_slug=slug_dict["parent"], ) if request.method == "POST": which_form = request.POST.get("form-type", "both") doc_form_invalid = False # Grab the posted slug value in case it's invalid posted_slug = request.POST.get("slug", slug_dict["specific"]) 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}) doc_form = DocumentForm( post_data, instance=doc, parent_slug=slug_dict["parent"] ) 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 = RevisionForm( request=request, data=post_data, 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()): doc = doc_form.save(parent=parent_doc) if which_form == "doc": url = urlparams(doc.get_edit_url(), opendescription=1) return redirect(url) else: doc_form.data["slug"] = posted_slug doc_form_invalid = True if doc and which_form in ["rev", "both"]: post_data = request.POST.copy() if "slug" not in post_data: post_data["slug"] = posted_slug # update the post data with the toc_depth of original post_data["toc_depth"] = based_on_rev.toc_depth # Pass in the locale for the akistmet "blog_lang". post_data["locale"] = document_locale rev_form = RevisionForm( request=request, data=post_data, parent_slug=slug_dict["parent"] ) rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid() and not doc_form_invalid: parent_id = request.POST.get("parent_id", "") # Attempt to set a parent if parent_id: try: try: parent_doc = Document.all_objects.get(id=parent_id) except Document.DoesNotExist: raise Http404("Parent document does not exist") rev_form.instance.document.parent = parent_doc doc.parent = parent_doc rev_form.instance.based_on.document = doc.original except Document.DoesNotExist: pass rev_form.save(doc) # If this is an Ajax POST, then return a JsonResponse if request.is_ajax(): data = { "error": False, "new_revision_id": rev_form.instance.id, } return JsonResponse(data) # Construct the redirect URL, adding any needed parameters url = doc.get_absolute_url() params = {} # Parameter for the document saved, so that we can delete the cached draft on load params["rev_saved"] = request.POST.get("current_rev", "") url = "%s?%s" % (url, urlencode(params)) return redirect(url) else: # If this is an Ajax POST, then return a JsonResponse with error if request.is_ajax(): if "current_rev" in rev_form._errors: # Make the error message safe so the '<' and '>' don't # get turned into '<' and '>', respectively rev_form.errors["current_rev"][0] = mark_safe( rev_form.errors["current_rev"][0] ) errors = [rev_form.errors[key][0] for key in rev_form.errors.keys()] data = { "error": True, "error_message": errors, "new_revision_id": rev_form.instance.id, } return JsonResponse(data=data) 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) 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, "attachment_form": AttachmentRevisionForm(), "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 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. # The parent document to translate from parent_doc = get_object_or_404(Document, locale=settings.WIKI_DEFAULT_LANGUAGE, slug=document_slug) 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', 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: revision = get_object_or_404(Revision, pk=revision_id) else: revision = None 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 if parent_doc.parent_topic: 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 ObjectDoesNotExist: pass user_has_doc_perm = (not doc) or (doc and doc.allows_editing_by(request.user)) user_has_rev_perm = (not doc) or (doc and doc.allows_revision_by(request.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, parent_slug=slug_dict['parent']) 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 is not None: content = revision.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(request=request, instance=instance, initial=initial, parent_slug=slug_dict['parent']) 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']) 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}) doc_form = DocumentForm(post_data, instance=doc, parent_slug=slug_dict['parent']) 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 = RevisionForm(request=request, data=request.POST, 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()): doc = doc_form.save(parent=parent_doc) if which_form == 'doc': url = urlparams(doc.get_edit_url(), opendescription=1) return redirect(url) 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 # update the post data with the toc_depth of original post_data['toc_depth'] = based_on_rev.toc_depth rev_form = RevisionForm(request=request, data=post_data, parent_slug=slug_dict['parent']) rev_form.instance.document = doc # for rev_form.clean() if rev_form.is_valid() and not doc_form_invalid: 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 rev_form.save(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) 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, 'attachment_form': AttachmentRevisionForm(), '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 new_document(request): """Create a new wiki document.""" initial_slug = request.GET.get('slug', '') initial_title = initial_slug.replace('_', ' ') initial_parent_id = '' try: initial_parent_id = int(request.GET.get('parent', '')) except ValueError: pass clone_id = None try: clone_id = int(request.GET.get('clone', '')) except ValueError: pass if not Document.objects.allows_add_by(request.user, initial_slug): # Try to head off disallowed Template:* creation, right off the bat raise PermissionDenied is_template = initial_slug.startswith(TEMPLATE_TITLE_PREFIX) # If a parent ID is provided via GET, confirm it exists parent_slug = parent_path = '' if initial_parent_id: try: parent_doc = Document.objects.get(pk=initial_parent_id) parent_slug = parent_doc.slug parent_path = parent_doc.get_absolute_url() except Document.DoesNotExist: pass if request.method == 'GET': initial_data = {} initial_html = '' initial_tags = '' initial_toc = Revision.TOC_DEPTH_H4 if clone_id: try: clone_doc = Document.objects.get(pk=clone_id) initial_title = clone_doc.title initial_html = clone_doc.html initial_tags = clone_doc.tags.all() if clone_doc.current_revision: initial_toc = clone_doc.current_revision.toc_depth else: initial_toc = 1 except Document.DoesNotExist: pass if parent_slug: initial_data['parent_topic'] = initial_parent_id if initial_slug: initial_data['title'] = initial_title initial_data['slug'] = initial_slug if is_template: review_tags = ('template',) else: review_tags = REVIEW_FLAG_TAGS_DEFAULT doc_form = DocumentForm(initial=initial_data) rev_form = RevisionForm(initial={ 'slug': initial_slug, 'title': initial_title, 'content': initial_html, 'review_tags': review_tags, 'tags': initial_tags, 'toc_depth': initial_toc }) allow_add_attachment = ( Attachment.objects.allow_add_attachment_by(request.user)) context = { 'is_template': is_template, 'parent_slug': parent_slug, 'parent_id': initial_parent_id, 'document_form': doc_form, 'revision_form': rev_form, 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'initial_tags': initial_tags, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'parent_path': parent_path} return render(request, 'wiki/new_document.html', context) post_data = request.POST.copy() posted_slug = post_data['slug'] post_data.update({'locale': request.locale}) if parent_slug: post_data.update({'parent_topic': initial_parent_id}) post_data.update({'slug': parent_slug + '/' + post_data['slug']}) doc_form = DocumentForm(post_data) rev_form = RevisionValidationForm(request.POST.copy()) rev_form.parent_slug = parent_slug if doc_form.is_valid() and rev_form.is_valid(): rev_form = RevisionForm(post_data) if rev_form.is_valid(): slug = doc_form.cleaned_data['slug'] if not Document.objects.allows_add_by(request.user, slug): raise PermissionDenied doc = doc_form.save(None) save_revision_and_notify(rev_form, request, doc) if doc.current_revision.is_approved: view = 'wiki.document' else: view = 'wiki.document_revisions' return HttpResponseRedirect(reverse(view, args=[doc.slug])) else: doc_form.data['slug'] = posted_slug else: doc_form.data['slug'] = posted_slug allow_add_attachment = ( Attachment.objects.allow_add_attachment_by(request.user)) context = { 'is_template': is_template, 'document_form': doc_form, 'revision_form': rev_form, 'WIKI_DOCUMENT_TAG_SUGGESTIONS': config.WIKI_DOCUMENT_TAG_SUGGESTIONS, 'allow_add_attachment': allow_add_attachment, 'attachment_form': AttachmentRevisionForm(), 'parent_slug': parent_slug, 'parent_path': parent_path, } return render(request, 'wiki/new_document.html', context)