diff --git a/kitsune/sumo/static/sumo/js/wiki.js b/kitsune/sumo/static/sumo/js/wiki.js index fd60a5920cb..23d1862a3c8 100644 --- a/kitsune/sumo/static/sumo/js/wiki.js +++ b/kitsune/sumo/static/sumo/js/wiki.js @@ -72,9 +72,12 @@ import collapsibleAccordionInit from "sumo/js/protocol-details-init"; initCodeMirrorEditor(); } + if ($body.is('.edit, .translate')) { + initDraft(); + } + if ($body.is('.translate')) { // Translate page initToggleDiff(); - initTranslationDraft(); } initEditingTools(); @@ -599,7 +602,7 @@ import collapsibleAccordionInit from "sumo/js/protocol-details-init"; } } - function initTranslationDraft() { + function initDraft() { var $draftButton = $('.btn-draft'), url = $('.btn-draft').data('draft-url'), $draftMessage = $('#draft-message'); @@ -610,7 +613,8 @@ import collapsibleAccordionInit from "sumo/js/protocol-details-init"; bothData = $('#both_form').serializeArray(), docData = $('#doc_form').serializeArray(), revData = $('#rev_form').serializeArray(), - totalData = $.extend(bothData, docData, revData); + editData = $('#edit_form').serializeArray(), + totalData = $.extend(bothData, docData, revData, editData); $draftMessage.html(image + message).removeClass('success error').addClass('info').show() $.post(url, totalData) diff --git a/kitsune/sumo/static/sumo/scss/components/_wiki.scss b/kitsune/sumo/static/sumo/scss/components/_wiki.scss index 3632939333c..b05efaa5458 100644 --- a/kitsune/sumo/static/sumo/scss/components/_wiki.scss +++ b/kitsune/sumo/static/sumo/scss/components/_wiki.scss @@ -262,8 +262,9 @@ article { } -/* Document Translation page */ -#localize-document { +/* Draft-related messages */ +#localize-document, +#edit-document { .buttons-and-preview { /* Taken from Bootstrap V3 */ diff --git a/kitsune/wiki/content_managers.py b/kitsune/wiki/content_managers.py index 50e9f1f656b..613d942bba6 100644 --- a/kitsune/wiki/content_managers.py +++ b/kitsune/wiki/content_managers.py @@ -40,8 +40,8 @@ def save_draft( Args: user: The user creating the draft - parent_doc: The parent document being translated - target_locale: The target locale for translation + parent_doc: The parent document for the revision + target_locale: The target locale for the revision draft_data: Dictionary containing draft content (title, slug, content, summary, keywords, based_on) Returns: DraftRevision: The created or updated draft revision @@ -57,7 +57,7 @@ def get_draft(self, user, parent_doc, target_locale: str) -> DraftRevision | Non Args: user: The user parent_doc: The parent document - target_locale: The target local + target_locale: The target locale Returns: DraftRevision or None: The existing draft if found """ @@ -281,7 +281,7 @@ def mark_ready_for_localization( class ManualContentManager(WikiContentManager): - """Content manager for manual translation workflow.""" + """Content manager for manual edit/translation workflow.""" pass diff --git a/kitsune/wiki/jinja2/wiki/edit.html b/kitsune/wiki/jinja2/wiki/edit.html index f42823d3023..ebf8e0bfeb1 100644 --- a/kitsune/wiki/jinja2/wiki/edit.html +++ b/kitsune/wiki/jinja2/wiki/edit.html @@ -23,6 +23,19 @@ {{ _('This document is restricted.') }} {% endif %} + {% if draft_revision %} +
  • + +
    +

    {{ _('You have a draft revision for this article saved on {date_time}')|f(date_time=draft_revision.created) }}

    +
    + {% csrf_token %} + + +
    +
    +
  • + {% endif %} {{ edit_messages(document, show_revision_warning) }} {{ document_lock_warning() }} @@ -42,7 +55,7 @@

    {{ _('Editing Content For:
    {title}')|f Support Document Guide.{% endtrans %}

    {{ errorlist(revision_form) }} -
    + {% csrf_token %} {% for field in revision_form.visible_fields() %}
    @@ -63,15 +76,18 @@

    {{ _('Editing Content For:
    {title}')|f - {{ submit_revision(revision_form, include_diff=True) }} -
    -
    -
    {{ revision_form.content.value() }}
    -
    -
    -
    -
    - {{ submit_revision(revision_form, buttons_only=True, include_diff=True) }} +
    + {{ submit_revision(revision_form, include_diff=True, allow_draft=True) }} +
    +
    +
    {{ revision_form.content.value() }}
    +
    +
    +
    +
    + {{ submit_revision(revision_form, buttons_only=True, include_diff=True, allow_draft=True) }} +
    + diff --git a/kitsune/wiki/jinja2/wiki/edit_metadata.html b/kitsune/wiki/jinja2/wiki/edit_metadata.html index e2a7de713fa..ebcc7136e92 100644 --- a/kitsune/wiki/jinja2/wiki/edit_metadata.html +++ b/kitsune/wiki/jinja2/wiki/edit_metadata.html @@ -2,7 +2,7 @@ {% from "layout/errorlist.html" import errorlist %} {% from "wiki/includes/sidebar_modules.html" import document_tools with context %} {% from "includes/common_macros.html" import content_editor with context %} -{% from "wiki/includes/document_macros.html" import edit_messages, submit_revision %} +{% from "wiki/includes/document_macros.html" import edit_messages %} {% from "wiki/includes/document_macros.html" import document_lock_warning with context %} {% set title = _('Edit Article Metadata | {document}')|f(document=document.title) %} {# TODO: Change KB url to landing page when we have one #} diff --git a/kitsune/wiki/jinja2/wiki/includes/document_macros.html b/kitsune/wiki/jinja2/wiki/includes/document_macros.html index a048baa3b2a..de0ad526286 100644 --- a/kitsune/wiki/jinja2/wiki/includes/document_macros.html +++ b/kitsune/wiki/jinja2/wiki/includes/document_macros.html @@ -244,10 +244,10 @@

    {{ _('Content:') }}

    {% endif %} {%- endmacro %} -{% macro submit_revision(form, buttons_only=False, show_no_update_checkbox=False, include_diff=False, translate=False) -%} +{% macro submit_revision(form, buttons_only=False, show_no_update_checkbox=False, include_diff=False, allow_draft=False) -%}
    - {% if translate %} + {% if allow_draft %} {% endif %} diff --git a/kitsune/wiki/jinja2/wiki/translate.html b/kitsune/wiki/jinja2/wiki/translate.html index 4749495a948..da3b6225d1d 100644 --- a/kitsune/wiki/jinja2/wiki/translate.html +++ b/kitsune/wiki/jinja2/wiki/translate.html @@ -188,7 +188,7 @@

    {{ _('{locale} translation:')|f(locale=language {# If the document has been created and has a current revision, we allow the localizer to keep the translation out of date with this new revision. #} - {{ submit_revision(revision_form, show_no_update_checkbox=(document and document.current_revision), include_diff=True, translate=True) }} + {{ submit_revision(revision_form, show_no_update_checkbox=(document and document.current_revision), include_diff=True, allow_draft=True) }}
    {{ revision_form.content.value() }}
    @@ -196,7 +196,7 @@

    {{ _('{locale} translation:')|f(locale=language

    - {{ submit_revision(revision_form, buttons_only=True, include_diff=True, translate=True) }} + {{ submit_revision(revision_form, buttons_only=True, include_diff=True, allow_draft=True) }}
    diff --git a/kitsune/wiki/views.py b/kitsune/wiki/views.py index e1e1845edf8..d87561492fe 100644 --- a/kitsune/wiki/views.py +++ b/kitsune/wiki/views.py @@ -564,18 +564,45 @@ def edit_document(request, document_slug, revision_id=None): return init_check user, doc, rev = init_check - rev_form = RevisionForm(instance=rev, initial={"based_on": rev.id, "comment": ""}) + rev_initial = {"based_on": rev.id, "comment": ""} + rev_form = RevisionForm(instance=rev, initial=rev_initial) + + # Check if the user has draft revision saved for the document (with the default locale) + content_manager = ManualContentManager() + draft = content_manager.get_draft(user, doc, settings.WIKI_DEFAULT_LANGUAGE) # POST if request.method == "POST": - rev_form = RevisionForm(request.POST) - rev_form.instance.document = doc # for rev_form.clean() - if rev_form.is_valid(): - _document_lock_clear(doc.id, user.username) - _save_rev_and_notify(rev_form, user, doc, base_rev=rev) - if "notify-future-changes" in request.POST: - EditDocumentEvent.notify(request.user, doc) - return HttpResponseRedirect(reverse("wiki.document_revisions", args=[document_slug])) + # Use POST for restoring and deleting drafts to avoid CSRF + restore_draft = "restore" in request.POST and bool(draft) + discard_draft = "discard" in request.POST and bool(draft) + # Make sure that one of the two is True but not both + if discard_draft ^ restore_draft: + if discard_draft and content_manager.discard_draft(draft.id, user): + return HttpResponseRedirect( + urlparams(reverse("wiki.edit_document", args=[document_slug])) + ) + elif restore_draft: + draft_data = content_manager.restore_draft(draft.id, user) + + rev_initial.update( + { + "content": draft_data.get("content", ""), + "summary": draft_data.get("summary", ""), + "keywords": draft_data.get("keywords", ""), + "based_on": draft_data.get("based_on"), + } + ) + rev_form = RevisionForm(instance=rev, initial=rev_initial) + else: + rev_form = RevisionForm(request.POST) + rev_form.instance.document = doc # for rev_form.clean() + if rev_form.is_valid(): + _document_lock_clear(doc.id, user.username) + _save_rev_and_notify(rev_form, user, doc, base_rev=rev) + if "notify-future-changes" in request.POST: + EditDocumentEvent.notify(request.user, doc) + return HttpResponseRedirect(reverse("wiki.document_revisions", args=[document_slug])) show_revision_warning = _show_revision_warning(doc, rev) locked, locked_by = _document_lock(doc.id, user.username) @@ -589,6 +616,7 @@ def edit_document(request, document_slug, revision_id=None): "show_revision_warning": show_revision_warning, "locked": locked, "locked_by": locked_by, + "draft_revision": draft, }, ) @@ -665,7 +693,7 @@ def edit_document_metadata(request, document_slug, revision_id=None): def draft_revision(request): """Create a Draft Revision. - User can have only one draft revision for a translated document. Store the draft with + User can have only one draft revision for a document. Store the draft with parent document, user and locale. Get the parent document from the based on revision""" draft_form = DraftRevisionForm(request.POST) if draft_form.is_valid():