Repository: wagtail/wagtail
File: wagtail/admin/views/pages/edit.py (Python)

Code before:
    @cached_property
    def is_out_of_date(self):
        # Check the autosave revision if present, otherwise fall back to the
        # initially loaded revision.
        submitted_revision_id = self.request.POST.get(
            "overwrite_revision_id"
        ) or self.request.POST.get("loaded_revision_id")

        return submitted_revision_id and (
            submitted_revision_id != str(self.page.latest_revision_id)
        )

    def post(self, request, *args, **kwargs):
        # Don't allow POST requests if the page is an alias
        if self.page.alias_of_id:
            # Return 405 "Method Not Allowed" response
            return HttpResponse(status=405)

        # For autosave, we only want to save the page if there are no conflicts
        if self.expects_json_response and self.is_out_of_date:
            return self.json_error_response(
                "invalid_revision",
                _("Saving will overwrite a newer version"),
            )

        self.form = self.form_class(
            self.request.POST,
            self.request.FILES,
            instance=self.page,
            subscription=self.subscription,
            parent_page=self.parent,
            for_user=self.request.user,
        )

        if self.action_name == "save":
            self.form.defer_required_fields()

        if self.form.is_valid() and not self.locked_for_user:
            return self.form_valid(self.form)
        else:
            self.form.restore_required_fields()
            return self.form_invalid(self.form)

    def workflow_action_is_valid(self):
        self.workflow_action = self.request.POST["workflow-action-name"]
        available_actions = self.page.current_workflow_task.get_actions(
            self.page, self.request.user
        )
        available_action_names = [
            name for name, verbose_name, modal in available_actions
        ]

Review comment (suggestion):
In the non-JSON case, there are a few options we can do:

- Always allow and show a warning when this happens (#2565)
- Always allow, but only show the warning if the user has not explicitly acknowledged that prior to saving, i.e. via the "concurrent editing notification" popup.
  - This can happen if the other session made a new revision before we had the chance to notify the current user (e.g. due to a high enough `WAGTAIL_EDITING_SESSION_PING_INTERVAL` or it's set to `0`).
- Only allow if the user has explicitly acknowledged it prior to saving

I think that decision can be made and implemented separately, so for now I'm only focusing on the JSON case for autosave.

Code after:
        )

    @cached_property
    def is_out_of_date(self):
        # Check the autosave revision if present, otherwise fall back to the
        # initially loaded revision.
        submitted_revision_id = self.request.POST.get(
            "overwrite_revision_id"
        ) or self.request.POST.get("loaded_revision_id")

        return submitted_revision_id and (
            submitted_revision_id != str(self.page.latest_revision_id)
        )

    def post(self, request, *args, **kwargs):
        # Don't allow POST requests if the page is an alias
        if self.page.alias_of_id:
            # Return 405 "Method Not Allowed" response
            return HttpResponse(status=405)

        # For autosave, we only want to save the page if there are no conflicts
        if self.expects_json_response and self.is_out_of_date:
            return self.json_error_response(
                "invalid_revision",
                _("Saving will overwrite a newer version."),
            )

        self.form = self.form_class(
            self.request.POST,
            self.request.FILES,
            instance=self.page,
            subscription=self.subscription,
            parent_page=self.parent,
            for_user=self.request.user,
        )

        if self.action_name == "save":
            self.form.defer_required_fields()

        if self.form.is_valid() and not self.locked_for_user:
            return self.form_valid(self.form)
        else:
            self.form.restore_required_fields()
            return self.form_invalid(self.form)

    def workflow_action_is_valid(self):
        self.workflow_action = self.request.POST["workflow-action-name"]
        available_actions = self.page.current_workflow_task.get_actions(
            self.page, self.request.user
        )
        available_action_names = [