diff --git a/wagtail/admin/views/pages/edit.py b/wagtail/admin/views/pages/edit.py index 90100bbdc8..ef25518315 100644 --- a/wagtail/admin/views/pages/edit.py +++ b/wagtail/admin/views/pages/edit.py @@ -87,324 +87,333 @@ class EditView(TemplateResponseMixin, ContextMixin, View): self.errors_debug = None - if self.request.method == 'GET': - if self.page_perms.user_has_lock(): - if self.page.locked_at: - lock_message = format_html(_("Page '{}' was locked by you on {}."), self.page.get_admin_display_title(), self.page.locked_at.strftime("%d %b %Y %H:%M")) - else: - lock_message = format_html(_("Page '{}' is locked by you."), self.page.get_admin_display_title()) + return super().dispatch(request) + def get(self, request): + if self.page_perms.user_has_lock(): + if self.page.locked_at: + lock_message = format_html(_("Page '{}' was locked by you on {}."), self.page.get_admin_display_title(), self.page.locked_at.strftime("%d %b %Y %H:%M")) + else: + lock_message = format_html(_("Page '{}' is locked by you."), self.page.get_admin_display_title()) + + lock_message += format_html( + '', + reverse('wagtailadmin_pages:unlock', args=(self.page.id,)), + _("Unlock") + ) + messages.warning(self.request, lock_message, extra_tags='lock') + + elif self.page.locked and self.page_perms.page_locked(): + # the page can also be locked at a permissions level if in a workflow, on a task the user is not a reviewer for + # this should be indicated separately + if self.page.locked_by and self.page.locked_at: + lock_message = format_html(_("Page '{}' was locked by {} on {}."), self.page.get_admin_display_title(), str(self.page.locked_by), self.page.locked_at.strftime("%d %b %Y %H:%M")) + else: + # Page was probably locked with an old version of Wagtail, or a script + lock_message = format_html(_("Page '{}' is locked."), self.page.get_admin_display_title()) + + if self.page_perms.can_unlock(): lock_message += format_html( '', reverse('wagtailadmin_pages:unlock', args=(self.page.id,)), _("Unlock") ) - messages.warning(self.request, lock_message, extra_tags='lock') + messages.error(self.request, lock_message, extra_tags='lock') - elif self.page.locked and self.page_perms.page_locked(): - # the page can also be locked at a permissions level if in a workflow, on a task the user is not a reviewer for - # this should be indicated separately - if self.page.locked_by and self.page.locked_at: - lock_message = format_html(_("Page '{}' was locked by {} on {}."), self.page.get_admin_display_title(), str(self.page.locked_by), self.page.locked_at.strftime("%d %b %Y %H:%M")) + if self.page.current_workflow_state: + workflow = self.workflow_state.workflow + task = self.workflow_state.current_task_state.task + if ( + self.workflow_state.status != WorkflowState.STATUS_NEEDS_CHANGES + and task.specific.page_locked_for_user(self.page, self.request.user) + ): + # Check for revisions still undergoing moderation and warn + if len(self.workflow_tasks) == 1: + # If only one task in workflow, show simple message + workflow_info = _("This page is currently awaiting moderation.") else: - # Page was probably locked with an old version of Wagtail, or a script - lock_message = format_html(_("Page '{}' is locked."), self.page.get_admin_display_title()) - - if self.page_perms.can_unlock(): - lock_message += format_html( - '', - reverse('wagtailadmin_pages:unlock', args=(self.page.id,)), - _("Unlock") + workflow_info = format_html( + _("This page is awaiting '{}' in the '{}' workflow."), + task.name, workflow.name ) - messages.error(self.request, lock_message, extra_tags='lock') + messages.error( + self.request, mark_safe(workflow_info + " " + _("Only reviewers for this task can edit the page.")), + extra_tags="lock" + ) - if self.page.current_workflow_state: - workflow = self.workflow_state.workflow - task = self.workflow_state.current_task_state.task - if ( - self.workflow_state.status != WorkflowState.STATUS_NEEDS_CHANGES - and task.specific.page_locked_for_user(self.page, self.request.user) - ): - # Check for revisions still undergoing moderation and warn - if len(self.workflow_tasks) == 1: - # If only one task in workflow, show simple message - workflow_info = _("This page is currently awaiting moderation.") - else: - workflow_info = format_html( - _("This page is awaiting '{}' in the '{}' workflow."), - task.name, workflow.name - ) - messages.error(self.request, mark_safe(workflow_info + " " + _("Only reviewers for this task can edit the page.")), - extra_tags="lock") + self.form = self.form_class(instance=self.page, parent_page=self.parent) + self.has_unsaved_changes = False + self.edit_handler = self.edit_handler.bind_to(form=self.form) + self.add_legacy_moderation_warning() + self.page_for_status = self.get_page_for_status() - if self.request.method == 'POST': - self.form = self.form_class( - self.request.POST, self.request.FILES, instance=self.page, parent_page=self.parent - ) + return self.render_to_response(self.get_context_data()) - is_publishing = False - is_submitting = False - is_restarting_workflow = False - is_reverting = False - is_saving = False - is_cancelling_workflow = bool(self.request.POST.get('action-cancel-workflow')) and self.workflow_state and self.workflow_state.user_can_cancel(self.request.user) - if is_cancelling_workflow: + def post(self, request): + self.form = self.form_class( + self.request.POST, self.request.FILES, instance=self.page, parent_page=self.parent + ) + + is_publishing = False + is_submitting = False + is_restarting_workflow = False + is_reverting = False + is_saving = False + is_cancelling_workflow = bool(self.request.POST.get('action-cancel-workflow')) and self.workflow_state and self.workflow_state.user_can_cancel(self.request.user) + if is_cancelling_workflow: + self.workflow_state.cancel(user=self.request.user) + # do this here so even if the page is locked due to not having permissions, the original submitter can still cancel the workflow + + if self.form.is_valid() and not self.page_perms.page_locked(): + self.page = self.form.save(commit=False) + + is_publishing = bool(self.request.POST.get('action-publish')) and self.page_perms.can_publish() + is_submitting = bool(self.request.POST.get('action-submit')) and self.page_perms.can_submit_for_moderation() + is_restarting_workflow = bool(self.request.POST.get('action-restart-workflow')) and self.page_perms.can_submit_for_moderation() and self.workflow_state and self.workflow_state.user_can_cancel(self.request.user) + is_reverting = bool(self.request.POST.get('revision')) + + is_performing_workflow_action = bool(self.request.POST.get('action-workflow-action')) + if is_performing_workflow_action: + 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] + if workflow_action not in available_action_names: + # prevent this action + is_performing_workflow_action = False + + is_saving = True + has_content_changes = self.form.has_changed() + + if is_restarting_workflow: self.workflow_state.cancel(user=self.request.user) - # do this here so even if the page is locked due to not having permissions, the original submitter can still cancel the workflow - if self.form.is_valid() and not self.page_perms.page_locked(): - self.page = self.form.save(commit=False) + # If a revision ID was passed in the form, get that revision so its + # date can be referenced in notification messages + if is_reverting: + previous_revision = get_object_or_404(self.page.revisions, id=self.request.POST.get('revision')) - is_publishing = bool(self.request.POST.get('action-publish')) and self.page_perms.can_publish() - is_submitting = bool(self.request.POST.get('action-submit')) and self.page_perms.can_submit_for_moderation() - is_restarting_workflow = bool(self.request.POST.get('action-restart-workflow')) and self.page_perms.can_submit_for_moderation() and self.workflow_state and self.workflow_state.user_can_cancel(self.request.user) - is_reverting = bool(self.request.POST.get('revision')) + if is_performing_workflow_action and not has_content_changes: + # don't save a new revision, as we're just going to update the page's + # workflow state with no content changes + revision = self.latest_revision + else: + # Save revision + revision = self.page.save_revision( + user=self.request.user, + log_action=True, # Always log the new revision on edit + previous_revision=(previous_revision if is_reverting else None) + ) - is_performing_workflow_action = bool(self.request.POST.get('action-workflow-action')) - if is_performing_workflow_action: - 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] - if workflow_action not in available_action_names: - # prevent this action - is_performing_workflow_action = False + # store submitted go_live_at for messaging below + go_live_at = self.page.go_live_at - is_saving = True - has_content_changes = self.form.has_changed() - - if is_restarting_workflow: - self.workflow_state.cancel(user=self.request.user) - - # If a revision ID was passed in the form, get that revision so its - # date can be referenced in notification messages - if is_reverting: - previous_revision = get_object_or_404(self.page.revisions, id=self.request.POST.get('revision')) - - if is_performing_workflow_action and not has_content_changes: - # don't save a new revision, as we're just going to update the page's - # workflow state with no content changes - revision = self.latest_revision - else: - # Save revision - revision = self.page.save_revision( - user=self.request.user, - log_action=True, # Always log the new revision on edit - previous_revision=(previous_revision if is_reverting else None) - ) - - # store submitted go_live_at for messaging below - go_live_at = self.page.go_live_at - - # Publish - if is_publishing: - for fn in hooks.get_hooks('before_publish_page'): - result = fn(self.request, self.page) - if hasattr(result, 'status_code'): - return result - - revision.publish( - user=self.request.user, - changed=has_content_changes, - previous_revision=(previous_revision if is_reverting else None) - ) - - # Need to reload the page because the URL may have changed, and we - # need the up-to-date URL for the "View Live" button. - self.page = self.page.specific_class.objects.get(pk=self.page.pk) - - for fn in hooks.get_hooks('after_publish_page'): - result = fn(self.request, self.page) - if hasattr(result, 'status_code'): - return result - - # Submit - if is_submitting or is_restarting_workflow: - if self.workflow_state and self.workflow_state.status == WorkflowState.STATUS_NEEDS_CHANGES: - # If the workflow was in the needs changes state, resume the existing workflow on submission - self.workflow_state.resume(self.request.user) - else: - # Otherwise start a new workflow - workflow = self.page.get_workflow() - workflow.start(self.page, self.request.user) - - if is_performing_workflow_action: - extra_workflow_data_json = self.request.POST.get('workflow-action-extra-data', '{}') - extra_workflow_data = json.loads(extra_workflow_data_json) - self.page.current_workflow_task.on_action(self.page.current_workflow_task_state, self.request.user, workflow_action, **extra_workflow_data) - - # Notifications + # Publish if is_publishing: - if go_live_at and go_live_at > timezone.now(): - # Page has been scheduled for publishing in the future - - if is_reverting: - message = _( - "Version from {0} of page '{1}' has been scheduled for publishing." - ).format( - previous_revision.created_at.strftime("%d %b %Y %H:%M"), - self.page.get_admin_display_title() - ) - else: - if self.page.live: - message = _( - "Page '{0}' is live and this version has been scheduled for publishing." - ).format( - self.page.get_admin_display_title() - ) - - else: - message = _( - "Page '{0}' has been scheduled for publishing." - ).format( - self.page.get_admin_display_title() - ) - - messages.success(self.request, message, buttons=[ - messages.button( - reverse('wagtailadmin_pages:edit', args=(self.page.id,)), - _('Edit') - ) - ]) - - else: - # Page is being published now - - if is_reverting: - message = _( - "Version from {0} of page '{1}' has been published." - ).format( - previous_revision.created_at.strftime("%d %b %Y %H:%M"), - self.page.get_admin_display_title() - ) - else: - message = _( - "Page '{0}' has been published." - ).format( - self.page.get_admin_display_title() - ) - - buttons = [] - if self.page.url is not None: - buttons.append(messages.button(self.page.url, _('View live'), new_window=True)) - buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(self.page.id,)), _('Edit'))) - messages.success(self.request, message, buttons=buttons) - - elif is_submitting: - - message = _( - "Page '{0}' has been submitted for moderation." - ).format( - self.page.get_admin_display_title() - ) - - messages.success(self.request, message, buttons=[ - messages.button( - reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), - _('View draft'), - new_window=True - ), - messages.button( - reverse('wagtailadmin_pages:edit', args=(self.page.id,)), - _('Edit') - ) - ]) - - elif is_cancelling_workflow: - message = _( - "Workflow on page '{0}' has been cancelled." - ).format( - self.page.get_admin_display_title() - ) - - messages.success(self.request, message, buttons=[ - messages.button( - reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), - _('View draft'), - new_window=True - ), - messages.button( - reverse('wagtailadmin_pages:edit', args=(self.page.id,)), - ('Edit') - ) - ]) - - elif is_restarting_workflow: - - message = _( - "Workflow on page '{0}' has been restarted." - ).format( - self.page.get_admin_display_title() - ) - - messages.success(self.request, message, buttons=[ - messages.button( - reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), - _('View draft'), - new_window=True - ), - messages.button( - reverse('wagtailadmin_pages:edit', args=(self.page.id,)), - _('Edit') - ) - ]) - - elif is_reverting: - message = _( - "Page '{0}' has been replaced with version from {1}." - ).format( - self.page.get_admin_display_title(), - previous_revision.created_at.strftime("%d %b %Y %H:%M") - ) - - messages.success(self.request, message) - elif is_saving: - message = _( - "Page '{0}' has been updated." - ).format( - self.page.get_admin_display_title() - ) - - messages.success(self.request, message) - - if is_saving: - for fn in hooks.get_hooks('after_edit_page'): + for fn in hooks.get_hooks('before_publish_page'): result = fn(self.request, self.page) if hasattr(result, 'status_code'): return result - if is_publishing or is_submitting or is_restarting_workflow or is_performing_workflow_action: - # we're done here - redirect back to the explorer - if self.next_url: - # redirect back to 'next' url if present - return redirect(self.next_url) - # redirect back to the explorer - return redirect('wagtailadmin_explore', self.page.get_parent().id) - else: - # Just saving - remain on edit page for further edits - target_url = reverse('wagtailadmin_pages:edit', args=[self.page.id]) - if self.next_url: - # Ensure the 'next' url is passed through again if present - target_url += '?next=%s' % urlquote(self.next_url) - return redirect(target_url) - else: - if self.page_perms.page_locked(): - messages.error(self.request, _("The page could not be saved as it is locked")) - else: - messages.validation_error( - self.request, _("The page could not be saved due to validation errors"), self.form - ) - self.errors_debug = ( - repr(self.form.errors) - + repr([ - (name, formset.errors) - for (name, formset) in self.form.formsets.items() - if formset.errors - ]) + revision.publish( + user=self.request.user, + changed=has_content_changes, + previous_revision=(previous_revision if is_reverting else None) ) - self.has_unsaved_changes = True + + # Need to reload the page because the URL may have changed, and we + # need the up-to-date URL for the "View Live" button. + self.page = self.page.specific_class.objects.get(pk=self.page.pk) + + for fn in hooks.get_hooks('after_publish_page'): + result = fn(self.request, self.page) + if hasattr(result, 'status_code'): + return result + + # Submit + if is_submitting or is_restarting_workflow: + if self.workflow_state and self.workflow_state.status == WorkflowState.STATUS_NEEDS_CHANGES: + # If the workflow was in the needs changes state, resume the existing workflow on submission + self.workflow_state.resume(self.request.user) + else: + # Otherwise start a new workflow + workflow = self.page.get_workflow() + workflow.start(self.page, self.request.user) + + if is_performing_workflow_action: + extra_workflow_data_json = self.request.POST.get('workflow-action-extra-data', '{}') + extra_workflow_data = json.loads(extra_workflow_data_json) + self.page.current_workflow_task.on_action(self.page.current_workflow_task_state, self.request.user, workflow_action, **extra_workflow_data) + + # Notifications + if is_publishing: + if go_live_at and go_live_at > timezone.now(): + # Page has been scheduled for publishing in the future + + if is_reverting: + message = _( + "Version from {0} of page '{1}' has been scheduled for publishing." + ).format( + previous_revision.created_at.strftime("%d %b %Y %H:%M"), + self.page.get_admin_display_title() + ) + else: + if self.page.live: + message = _( + "Page '{0}' is live and this version has been scheduled for publishing." + ).format( + self.page.get_admin_display_title() + ) + + else: + message = _( + "Page '{0}' has been scheduled for publishing." + ).format( + self.page.get_admin_display_title() + ) + + messages.success(self.request, message, buttons=[ + messages.button( + reverse('wagtailadmin_pages:edit', args=(self.page.id,)), + _('Edit') + ) + ]) + + else: + # Page is being published now + + if is_reverting: + message = _( + "Version from {0} of page '{1}' has been published." + ).format( + previous_revision.created_at.strftime("%d %b %Y %H:%M"), + self.page.get_admin_display_title() + ) + else: + message = _( + "Page '{0}' has been published." + ).format( + self.page.get_admin_display_title() + ) + + buttons = [] + if self.page.url is not None: + buttons.append(messages.button(self.page.url, _('View live'), new_window=True)) + buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(self.page.id,)), _('Edit'))) + messages.success(self.request, message, buttons=buttons) + + elif is_submitting: + + message = _( + "Page '{0}' has been submitted for moderation." + ).format( + self.page.get_admin_display_title() + ) + + messages.success(self.request, message, buttons=[ + messages.button( + reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), + _('View draft'), + new_window=True + ), + messages.button( + reverse('wagtailadmin_pages:edit', args=(self.page.id,)), + _('Edit') + ) + ]) + + elif is_cancelling_workflow: + message = _( + "Workflow on page '{0}' has been cancelled." + ).format( + self.page.get_admin_display_title() + ) + + messages.success(self.request, message, buttons=[ + messages.button( + reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), + _('View draft'), + new_window=True + ), + messages.button( + reverse('wagtailadmin_pages:edit', args=(self.page.id,)), + ('Edit') + ) + ]) + + elif is_restarting_workflow: + + message = _( + "Workflow on page '{0}' has been restarted." + ).format( + self.page.get_admin_display_title() + ) + + messages.success(self.request, message, buttons=[ + messages.button( + reverse('wagtailadmin_pages:view_draft', args=(self.page.id,)), + _('View draft'), + new_window=True + ), + messages.button( + reverse('wagtailadmin_pages:edit', args=(self.page.id,)), + _('Edit') + ) + ]) + + elif is_reverting: + message = _( + "Page '{0}' has been replaced with version from {1}." + ).format( + self.page.get_admin_display_title(), + previous_revision.created_at.strftime("%d %b %Y %H:%M") + ) + + messages.success(self.request, message) + elif is_saving: + message = _( + "Page '{0}' has been updated." + ).format( + self.page.get_admin_display_title() + ) + + messages.success(self.request, message) + + if is_saving: + for fn in hooks.get_hooks('after_edit_page'): + result = fn(self.request, self.page) + if hasattr(result, 'status_code'): + return result + + if is_publishing or is_submitting or is_restarting_workflow or is_performing_workflow_action: + # we're done here - redirect back to the explorer + if self.next_url: + # redirect back to 'next' url if present + return redirect(self.next_url) + # redirect back to the explorer + return redirect('wagtailadmin_explore', self.page.get_parent().id) + else: + # Just saving - remain on edit page for further edits + target_url = reverse('wagtailadmin_pages:edit', args=[self.page.id]) + if self.next_url: + # Ensure the 'next' url is passed through again if present + target_url += '?next=%s' % urlquote(self.next_url) + return redirect(target_url) else: - self.form = self.form_class(instance=self.page, parent_page=self.parent) - self.has_unsaved_changes = False + if self.page_perms.page_locked(): + messages.error(self.request, _("The page could not be saved as it is locked")) + else: + messages.validation_error( + self.request, _("The page could not be saved due to validation errors"), self.form + ) + self.errors_debug = ( + repr(self.form.errors) + + repr([ + (name, formset.errors) + for (name, formset) in self.form.formsets.items() + if formset.errors + ]) + ) + self.has_unsaved_changes = True self.edit_handler = self.edit_handler.bind_to(form=self.form) self.add_legacy_moderation_warning()