def form_invalid(self, form): # even if the page is locked due to not having permissions, the original submitter can still cancel the workflow if self.is_cancelling_workflow: self.workflow_state.cancel(user=self.request.user) self.add_cancel_workflow_confirmation_message() 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() self.page_for_status = self.get_page_for_status() return self.render_to_response(self.get_context_data())
def edit(request, app_label, model_name, pk): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('change', model) if not request.user.has_perm(permission): return permission_denied(request) instance = get_object_or_404(model, pk=unquote(pk)) for fn in hooks.get_hooks('before_edit_snippet'): result = fn(request, instance) if hasattr(result, 'status_code'): return result edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(instance=instance, request=request) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("%(snippet_type)s '%(instance)s' updated.") % { 'snippet_type': capfirst(model._meta.verbose_name), 'instance': instance }, buttons=[ messages.button( reverse('wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))), _('Edit')) ]) for fn in hooks.get_hooks('after_edit_snippet'): result = fn(request, instance) if hasattr(result, 'status_code'): return result return redirect('wagtailsnippets:list', app_label, model_name) else: messages.validation_error( request, _("The snippet could not be saved due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(form=form) return TemplateResponse( request, 'wagtailsnippets/snippets/edit.html', { 'model_opts': model._meta, 'instance': instance, 'edit_handler': edit_handler, 'form': form, })
def form_invalid(self, form): messages.validation_error( self.request, _("The page could not be created due to validation errors"), self.form ) self.has_unsaved_changes = True self.edit_handler = self.edit_handler.bind_to(form=self.form) return self.render_to_response(self.get_context_data())
def edit(request, app_name, model_name, site_pk): model = get_model_from_url_params(app_name, model_name) if not user_can_edit_setting_type(request.user, model): raise PermissionDenied site = get_object_or_404(Site, pk=site_pk) setting_type_name = model._meta.verbose_name instance = model.for_site(site) edit_handler = get_setting_edit_handler(model) edit_handler = edit_handler.bind_to(instance=instance, request=request) form_class = edit_handler.get_form_class() if request.method == "POST": form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): with transaction.atomic(): form.save() log(instance, "wagtail.edit") messages.success( request, _("%(setting_type)s updated.") % { "setting_type": capfirst(setting_type_name), "instance": instance }, ) return redirect("wagtailsettings:edit", app_name, model_name, site.pk) else: messages.validation_error( request, _("The setting could not be saved due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(form=form) # Show a site switcher form if there are multiple sites site_switcher = None if Site.objects.count() > 1: site_switcher = SiteSwitchForm(site, model) return TemplateResponse( request, "wagtailsettings/edit.html", { "opts": model._meta, "setting_type_name": setting_type_name, "instance": instance, "edit_handler": edit_handler, "form": form, "site": site, "site_switcher": site_switcher, "tabbed": isinstance(edit_handler, TabbedInterface), }, )
def edit(request, app_label, model_name, pk): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('change', model) if not request.user.has_perm(permission): return permission_denied(request) instance = get_object_or_404(model, pk=unquote(pk)) edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(instance=instance, request=request) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success(request, _("{snippet_type} '{instance}' updated.").format( snippet_type=capfirst( model._meta.verbose_name_plural), instance=instance), buttons=[ messages.button( reverse('wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))), _('Edit')) ]) return redirect('wagtailsnippets:list', app_label, model_name) else: messages.validation_error( request, _("The snippet could not be saved due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(form=form) return render( request, 'wagtailsnippets/snippets/edit.html', { # original version of snippets.py does not include 'can delete snippets' 'can_delete_snippets': request.user.has_perm(get_permission_name('delete', model)), 'model_opts': model._meta, 'instance': instance, 'edit_handler': edit_handler, 'form': form, })
def edit(request, app_name, model_name, site_pk): model = get_model_from_url_params(app_name, model_name) if not user_can_edit_setting_type(request.user, model): raise PermissionDenied site = get_object_or_404(Site, pk=site_pk) setting_type_name = model._meta.verbose_name instance = model.for_site(site) edit_handler = get_setting_edit_handler(model) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("{setting_type} updated.").format( setting_type=capfirst(setting_type_name), instance=instance)) return redirect('wagtailsettings:edit', app_name, model_name, site.pk) else: messages.validation_error( request, _("The setting could not be saved due to errors."), form) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) # Show a site switcher form if there are multiple sites site_switcher = None if Site.objects.count() > 1: site_switcher = SiteSwitchForm(site, model) return render( request, 'wagtailsettings/edit.html', { 'opts': model._meta, 'setting_type_name': setting_type_name, 'instance': instance, 'edit_handler': edit_handler, 'form': form, 'site': site, 'site_switcher': site_switcher, 'tabbed': isinstance(edit_handler, TabbedInterface), })
def edit(request, app_name, model_name, site_pk): model = get_model_from_url_params(app_name, model_name) if not user_can_edit_setting_type(request.user, model): raise PermissionDenied site = get_object_or_404(Site, pk=site_pk) setting_type_name = model._meta.verbose_name instance = model.for_site(site) edit_handler = get_setting_edit_handler(model) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("{setting_type} updated.").format( setting_type=capfirst(setting_type_name), instance=instance ) ) return redirect('wagtailsettings:edit', app_name, model_name, site.pk) else: messages.validation_error( request, _("The setting could not be saved due to errors."), form ) edit_handler = edit_handler.bind_to_instance( instance=instance, form=form, request=request) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to_instance( instance=instance, form=form, request=request) # Show a site switcher form if there are multiple sites site_switcher = None if Site.objects.count() > 1: site_switcher = SiteSwitchForm(site, model) return render(request, 'wagtailsettings/edit.html', { 'opts': model._meta, 'setting_type_name': setting_type_name, 'instance': instance, 'edit_handler': edit_handler, 'form': form, 'site': site, 'site_switcher': site_switcher, 'tabbed': isinstance(edit_handler, TabbedInterface), })
def edit(request, app_label, model_name, pk): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('change', model) if not request.user.has_perm(permission): return permission_denied(request) instance = get_object_or_404(model, pk=unquote(pk)) edit_handler = get_snippet_edit_handler(model) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("{snippet_type} '{instance}' updated.").format( snippet_type=capfirst(model._meta.verbose_name_plural), instance=instance ), buttons=[ messages.button(reverse( 'wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk)) ), _('Edit')) ] ) return redirect('wagtailsnippets:list', app_label, model_name) else: messages.validation_error( request, _("The snippet could not be saved due to errors."), form ) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) return render(request, 'wagtailsnippets/snippets/edit.html', { 'model_opts': model._meta, 'instance': instance, 'edit_handler': edit_handler, 'form': form, })
def create(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('add', model) if not request.user.has_perm(permission): return permission_denied(request) instance = model() edit_handler = get_snippet_edit_handler(model) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success(request, _("{snippet_type} '{instance}' created.").format( snippet_type=capfirst( model._meta.verbose_name), instance=instance), buttons=[ messages.button( reverse('wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))), _('Edit')) ]) return redirect('wagtailsnippets:list', app_label, model_name) else: messages.validation_error( request, _("The snippet could not be created due to errors."), form) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to_instance(instance=instance, form=form, request=request) return render(request, 'wagtailsnippets/snippets/create.html', { 'model_opts': model._meta, 'edit_handler': edit_handler, 'form': form, })
def create(request, content_type_app_name, content_type_model_name, parent_page_id): parent_page = get_object_or_404(Page, id=parent_page_id).specific parent_page_perms = parent_page.permissions_for_user(request.user) if not parent_page_perms.can_add_subpage(): raise PermissionDenied try: content_type = ContentType.objects.get_by_natural_key( content_type_app_name, content_type_model_name) except ContentType.DoesNotExist: raise Http404 # Get class page_class = content_type.model_class() # Make sure the class is a descendant of Page if not issubclass(page_class, Page): raise Http404 # page must be in the list of allowed subpage types for this parent ID if page_class not in parent_page.creatable_subpage_models(): raise PermissionDenied if not page_class.can_create_at(parent_page): raise PermissionDenied for fn in hooks.get_hooks('before_create_page'): result = fn(request, parent_page, page_class) if hasattr(result, 'status_code'): return result page = page_class(owner=request.user) edit_handler = page_class.get_edit_handler() form_class = edit_handler.get_form_class() next_url = get_valid_next_url_from_request(request) if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=page, parent_page=parent_page) if form.is_valid(): page = form.save(commit=False) # Save page parent_page.add_child(instance=page) # Save revision page.save_revision( user=request.user, submitted_for_moderation=False, ) messages.success( request, _('Page \'{0}\' created.').format( page.get_admin_display_title())) for fn in hooks.get_hooks('after_create_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result # Just saving - remain on edit page for further edits target_url = reverse('experiments_oneyouvariant_edit', args=[page.id]) if next_url: # Ensure the 'next' url is passed through again if present target_url += '?next=%s' % urlquote(next_url) return redirect(target_url) else: messages.validation_error( request, _('The page could not be created due to validation errors'), form) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) has_unsaved_changes = True else: parent_page_json = parent_page.to_json() page = page_class.from_json(parent_page_json) slug = hashlib.sha224( base64.b64encode(str(time.time()).encode('utf-8'))).hexdigest() page.slug = '%s-v%s' % (page.slug, slug[:6]) page.title = '%s (describe the variant)' % page.title signals.init_new_page.send(sender=create, page=page, parent=parent_page) form = form_class(instance=page, parent_page=parent_page) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) has_unsaved_changes = False return render( request, 'wagtailadmin/custom_add_footer.html', { 'content_type': content_type, 'page_class': page_class, 'parent_page': parent_page, 'edit_handler': edit_handler, 'preview_modes': page.preview_modes, 'form': form, 'next': next_url, 'has_unsaved_changes': has_unsaved_changes, })
def form_invalid(self, form): messages.validation_error(self.request, self.get_error_message(), form) return self.render_to_response(self.get_context_data(form=form))
def form_invalid(self, form): messages.validation_error( self.request, self.get_error_message(), form ) return self.render_to_response(self.get_context_data())
def form_invalid(self, form): # TODO: This override is only required for Wagtail<2.1 messages.validation_error( self.request, self.get_error_message(), form ) return self.render_to_response(self.get_context_data())
def form_invalid(self, form): # TODO: This override is only required for Wagtail<2.1 messages.validation_error(self.request, self.get_error_message(), form) return self.render_to_response(self.get_context_data())
def create(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('add', model) if not request.user.has_perm(permission): raise PermissionDenied for fn in hooks.get_hooks('before_create_snippet'): result = fn(request, model) if hasattr(result, 'status_code'): return result instance = model() # Set locale of the new instance if issubclass(model, TranslatableMixin): selected_locale = request.GET.get('locale') if selected_locale: instance.locale = get_object_or_404(Locale, language_code=selected_locale) else: instance.locale = Locale.get_default() # Make edit handler edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(request=request) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("%(snippet_type)s '%(instance)s' created.") % { 'snippet_type': capfirst(model._meta.verbose_name), 'instance': instance }, buttons=[ messages.button( reverse('wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))), _('Edit')) ]) for fn in hooks.get_hooks('after_create_snippet'): result = fn(request, instance) if hasattr(result, 'status_code'): return result urlquery = '' if isinstance(instance, TranslatableMixin ) and instance.locale is not Locale.get_default(): urlquery = '?locale=' + instance.locale.language_code return redirect( reverse('wagtailsnippets:list', args=[app_label, model_name]) + urlquery) else: messages.validation_error( request, _("The snippet could not be created due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(instance=instance, form=form) context = { 'model_opts': model._meta, 'edit_handler': edit_handler, 'form': form, 'action_menu': SnippetActionMenu(request, view='create', model=model), 'locale': None, 'translations': [], } if getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass( model, TranslatableMixin): context.update({ 'locale': instance.locale, 'translations': [{ 'locale': locale, 'url': reverse('wagtailsnippets:add', args=[app_label, model_name]) + '?locale=' + locale.language_code } for locale in Locale.objects.all().exclude(id=instance.locale.id) ], }) return TemplateResponse(request, 'wagtailsnippets/snippets/create.html', context)
def edit(request, app_name, model_name, pk): model = get_model_from_url_params(app_name, model_name) if not user_can_edit_setting_type(request.user, model): raise PermissionDenied setting_type_name = model._meta.verbose_name edit_handler = get_setting_edit_handler(model) form_class = edit_handler.get_form_class() site: Optional[Site] = None site_switcher = None form_id: int = None if issubclass(model, BaseSiteSetting): site = get_object_or_404(Site, pk=pk) form_id = site.pk instance = model.for_site(site) if request.method == "POST": form = form_class( request.POST, request.FILES, instance=instance, for_user=request.user ) if form.is_valid(): with transaction.atomic(): form.save() log(instance, "wagtail.edit") messages.success( request, _("%(setting_type)s updated.") % { "setting_type": capfirst(setting_type_name), "instance": instance, }, ) return redirect("wagtailsettings:edit", app_name, model_name, site.pk) else: messages.validation_error( request, _("The setting could not be saved due to errors."), form ) else: form = form_class(instance=instance, for_user=request.user) edit_handler = edit_handler.get_bound_panel( instance=instance, request=request, form=form ) media = form.media + edit_handler.media # Show a site switcher form if there are multiple sites if Site.objects.count() > 1: site_switcher = SiteSwitchForm(site, model) media += site_switcher.media elif issubclass(model, BaseGenericSetting): queryset = model.base_queryset() # Create the instance if we haven't already. if queryset.count() == 0: model.objects.create() instance = get_object_or_404(model, pk=pk) form_id = instance.pk if request.method == "POST": form = form_class( request.POST, request.FILES, instance=instance, for_user=request.user ) if form.is_valid(): with transaction.atomic(): form.save() log(instance, "wagtail.edit") messages.success( request, _("%(setting_type)s updated.") % { "setting_type": capfirst(setting_type_name), "instance": instance, }, ) return redirect("wagtailsettings:edit", app_name, model_name) else: messages.validation_error( request, _("The setting could not be saved due to errors."), form ) else: form = form_class(instance=instance, for_user=request.user) edit_handler = edit_handler.get_bound_panel( instance=instance, request=request, form=form ) media = form.media + edit_handler.media else: raise NotImplementedError return TemplateResponse( request, "wagtailsettings/edit.html", { "opts": model._meta, "setting_type_name": setting_type_name, "instance": instance, "edit_handler": edit_handler, "form": form, "site": site, "site_switcher": site_switcher, "tabbed": isinstance(edit_handler.panel, TabbedInterface), "media": media, "form_id": form_id, }, )
def create(request, content_type_app_name, content_type_model_name, parent_page_id): parent_page = get_object_or_404(Page, id=parent_page_id).specific parent_page_perms = parent_page.permissions_for_user(request.user) if not parent_page_perms.can_add_subpage(): raise PermissionDenied try: content_type = ContentType.objects.get_by_natural_key(content_type_app_name, content_type_model_name) except ContentType.DoesNotExist: raise Http404 # Get class page_class = content_type.model_class() # Make sure the class is a descendant of Page if not issubclass(page_class, Page): raise Http404 # page must be in the list of allowed subpage types for this parent ID if page_class not in parent_page.creatable_subpage_models(): raise PermissionDenied if not page_class.can_create_at(parent_page): raise PermissionDenied for fn in hooks.get_hooks('before_create_page'): result = fn(request, parent_page, page_class) if hasattr(result, 'status_code'): return result page = page_class(owner=request.user) edit_handler = page_class.get_edit_handler() form_class = edit_handler.get_form_class() next_url = get_valid_next_url_from_request(request) if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=page, parent_page=parent_page) if form.is_valid(): page = form.save(commit=False) is_publishing = bool(request.POST.get('action-publish')) and parent_page_perms.can_publish_subpage() is_submitting = bool(request.POST.get('action-submit')) if not is_publishing: page.live = False # Save page parent_page.add_child(instance=page) # Save revision revision = page.save_revision( user=request.user, submitted_for_moderation=is_submitting, ) # Publish if is_publishing: revision.publish() # Notifications if is_publishing: if page.go_live_at and page.go_live_at > timezone.now(): messages.success(request, _("Page '{0}' created and scheduled for publishing.").format(page.get_admin_display_title()), buttons=[ messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit')) ]) else: buttons = [] if page.url is not None: buttons.append(messages.button(page.url, _('View live'), new_window=True)) buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit'))) messages.success(request, _("Page '{0}' created and published.").format(page.get_admin_display_title()), buttons=buttons) elif is_submitting: messages.success( request, _("Page '{0}' created and submitted for moderation.").format(page.get_admin_display_title()), buttons=[ messages.button( reverse('wagtailadmin_pages:view_draft', args=(page.id,)), _('View draft'), new_window=True ), messages.button( reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit') ) ] ) if not send_notification(page.get_latest_revision().id, 'submitted', request.user.pk): messages.error(request, _("Failed to send notifications to moderators")) else: messages.success(request, _("Page '{0}' created.").format(page.get_admin_display_title())) for fn in hooks.get_hooks('after_create_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result if is_publishing or is_submitting: # we're done here if next_url: # redirect back to 'next' url if present return redirect(next_url) # redirect back to the explorer return redirect('wagtailadmin_explore', page.get_parent().id) else: # Just saving - remain on edit page for further edits target_url = reverse('wagtailadmin_pages:edit', args=[page.id]) if next_url: # Ensure the 'next' url is passed through again if present target_url += '?next=%s' % urlquote(next_url) return redirect(target_url) else: messages.validation_error( request, _("The page could not be created due to validation errors"), form ) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) has_unsaved_changes = True else: signals.init_new_page.send(sender=create, page=page, parent=parent_page) form = form_class(instance=page, parent_page=parent_page) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) has_unsaved_changes = False return render(request, 'wagtailadmin/pages/create.html', { 'content_type': content_type, 'page_class': page_class, 'parent_page': parent_page, 'edit_handler': edit_handler, 'preview_modes': page.preview_modes, 'form': form, 'next': next_url, 'has_unsaved_changes': has_unsaved_changes, })
def edit(request, page_id): real_page_record = get_object_or_404(Page, id=page_id) latest_revision = real_page_record.get_latest_revision() page = real_page_record.get_latest_revision_as_page() parent = page.get_parent() content_type = ContentType.objects.get_for_model(page) page_class = content_type.model_class() page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied for fn in hooks.get_hooks('before_edit_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result edit_handler = page_class.get_edit_handler() form_class = edit_handler.get_form_class() next_url = get_valid_next_url_from_request(request) errors_debug = None if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=page, parent_page=parent) if form.is_valid() and not page.locked: page = form.save(commit=False) is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish() is_submitting = bool(request.POST.get('action-submit')) is_reverting = bool(request.POST.get('revision')) # 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(page.revisions, id=request.POST.get('revision')) # Save revision revision = page.save_revision( user=request.user, submitted_for_moderation=is_submitting, ) # store submitted go_live_at for messaging below go_live_at = page.go_live_at # Publish if is_publishing: revision.publish() # Need to reload the page because the URL may have changed, and we # need the up-to-date URL for the "View Live" button. page = page.specific_class.objects.get(pk=page.pk) # 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 = _( "Revision from {0} of page '{1}' has been scheduled for publishing." ).format( previous_revision.created_at.strftime("%d %b %Y %H:%M"), page.get_admin_display_title() ) else: if page.live: message = _( "Page '{0}' is live and this revision has been scheduled for publishing." ).format( page.get_admin_display_title() ) else: message = _( "Page '{0}' has been scheduled for publishing." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(page.id,)), _('Edit') ) ]) else: # Page is being published now if is_reverting: message = _( "Revision from {0} of page '{1}' has been published." ).format( previous_revision.created_at.strftime("%d %b %Y %H:%M"), page.get_admin_display_title() ) else: message = _( "Page '{0}' has been published." ).format( page.get_admin_display_title() ) buttons = [] if page.url is not None: buttons.append(messages.button(page.url, _('View live'), new_window=True)) buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit'))) messages.success(request, message, buttons=buttons) elif is_submitting: message = _( "Page '{0}' has been submitted for moderation." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:view_draft', args=(page_id,)), _('View draft'), new_window=True ), messages.button( reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit') ) ]) if not send_notification(page.get_latest_revision().id, 'submitted', request.user.pk): messages.error(request, _("Failed to send notifications to moderators")) else: # Saving if is_reverting: message = _( "Page '{0}' has been replaced with revision from {1}." ).format( page.get_admin_display_title(), previous_revision.created_at.strftime("%d %b %Y %H:%M") ) else: message = _( "Page '{0}' has been updated." ).format( page.get_admin_display_title() ) messages.success(request, message) for fn in hooks.get_hooks('after_edit_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result if is_publishing or is_submitting: # we're done here - redirect back to the explorer if next_url: # redirect back to 'next' url if present return redirect(next_url) # redirect back to the explorer return redirect('wagtailadmin_explore', page.get_parent().id) else: # Just saving - remain on edit page for further edits target_url = reverse('wagtailadmin_pages:edit', args=[page.id]) if next_url: # Ensure the 'next' url is passed through again if present target_url += '?next=%s' % urlquote(next_url) return redirect(target_url) else: if page.locked: messages.error(request, _("The page could not be saved as it is locked")) else: messages.validation_error( request, _("The page could not be saved due to validation errors"), form ) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) errors_debug = ( repr(edit_handler.form.errors) + repr([ (name, formset.errors) for (name, formset) in edit_handler.form.formsets.items() if formset.errors ]) ) has_unsaved_changes = True else: form = form_class(instance=page, parent_page=parent) edit_handler = edit_handler.bind_to_instance(instance=page, form=form, request=request) has_unsaved_changes = False # Check for revisions still undergoing moderation and warn if latest_revision and latest_revision.submitted_for_moderation: buttons = [] if page.live: buttons.append(messages.button( reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)), _('Compare with live version') )) messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons) if page.live and page.has_unpublished_changes: # Page status needs to present the version of the page containing the correct live URL page_for_status = real_page_record.specific else: page_for_status = page return render(request, 'wagtailadmin/pages/edit.html', { 'page': page, 'page_for_status': page_for_status, 'content_type': content_type, 'edit_handler': edit_handler, 'errors_debug': errors_debug, 'preview_modes': page.preview_modes, 'form': form, 'next': next_url, 'has_unsaved_changes': has_unsaved_changes, })
def form_invalid(self, form): self.form = form error_message = self.get_error_message() if error_message is not None: messages.validation_error(self.request, error_message, form) return super().form_invalid(form)
def create(request, app_label, model_name): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name("add", model) if not request.user.has_perm(permission): raise PermissionDenied for fn in hooks.get_hooks("before_create_snippet"): result = fn(request, model) if hasattr(result, "status_code"): return result instance = model() # Set locale of the new instance if issubclass(model, TranslatableMixin): selected_locale = request.GET.get("locale") if selected_locale: instance.locale = get_object_or_404(Locale, language_code=selected_locale) else: instance.locale = Locale.get_default() # Make edit handler edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(request=request) form_class = edit_handler.get_form_class() if request.method == "POST": form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): with transaction.atomic(): form.save() log(instance=instance, action="wagtail.create") messages.success( request, _("%(snippet_type)s '%(instance)s' created.") % { "snippet_type": capfirst(model._meta.verbose_name), "instance": instance, }, buttons=[ messages.button( reverse( "wagtailsnippets:edit", args=(app_label, model_name, quote(instance.pk)), ), _("Edit"), ) ], ) for fn in hooks.get_hooks("after_create_snippet"): result = fn(request, instance) if hasattr(result, "status_code"): return result urlquery = "" if (isinstance(instance, TranslatableMixin) and instance.locale is not Locale.get_default()): urlquery = "?locale=" + instance.locale.language_code return redirect( reverse("wagtailsnippets:list", args=[app_label, model_name]) + urlquery) else: messages.validation_error( request, _("The snippet could not be created due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(instance=instance, form=form) context = { "model_opts": model._meta, "edit_handler": edit_handler, "form": form, "action_menu": SnippetActionMenu(request, view="create", model=model), "locale": None, "translations": [], } if getattr(settings, "WAGTAIL_I18N_ENABLED", False) and issubclass( model, TranslatableMixin): context.update({ "locale": instance.locale, "translations": [{ "locale": locale, "url": reverse("wagtailsnippets:add", args=[app_label, model_name]) + "?locale=" + locale.language_code, } for locale in Locale.objects.all().exclude(id=instance.locale.id) ], }) return TemplateResponse(request, "wagtailsnippets/snippets/create.html", context)
def edit(request, app_label, model_name, pk): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name("change", model) if not request.user.has_perm(permission): raise PermissionDenied instance = get_object_or_404(model, pk=unquote(pk)) for fn in hooks.get_hooks("before_edit_snippet"): result = fn(request, instance) if hasattr(result, "status_code"): return result edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(instance=instance, request=request) form_class = edit_handler.get_form_class() if request.method == "POST": form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): with transaction.atomic(): form.save() log(instance=instance, action="wagtail.edit") messages.success( request, _("%(snippet_type)s '%(instance)s' updated.") % { "snippet_type": capfirst(model._meta.verbose_name), "instance": instance, }, buttons=[ messages.button( reverse( "wagtailsnippets:edit", args=(app_label, model_name, quote(instance.pk)), ), _("Edit"), ) ], ) for fn in hooks.get_hooks("after_edit_snippet"): result = fn(request, instance) if hasattr(result, "status_code"): return result return redirect("wagtailsnippets:list", app_label, model_name) else: messages.validation_error( request, _("The snippet could not be saved due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(form=form) latest_log_entry = log_registry.get_logs_for_instance(instance).first() context = { "model_opts": model._meta, "instance": instance, "edit_handler": edit_handler, "form": form, "action_menu": SnippetActionMenu(request, view="edit", instance=instance), "locale": None, "translations": [], "latest_log_entry": latest_log_entry, } if getattr(settings, "WAGTAIL_I18N_ENABLED", False) and issubclass( model, TranslatableMixin): context.update({ "locale": instance.locale, "translations": [{ "locale": translation.locale, "url": reverse( "wagtailsnippets:edit", args=[app_label, model_name, quote(translation.pk)], ), } for translation in instance.get_translations().select_related( "locale")], }) return TemplateResponse(request, "wagtailsnippets/snippets/edit.html", context)
def edit(request, app_label, model_name, pk): model = get_snippet_model_from_url_params(app_label, model_name) permission = get_permission_name('change', model) if not request.user.has_perm(permission): raise PermissionDenied instance = get_object_or_404(model, pk=unquote(pk)) for fn in hooks.get_hooks('before_edit_snippet'): result = fn(request, instance) if hasattr(result, 'status_code'): return result edit_handler = get_snippet_edit_handler(model) edit_handler = edit_handler.bind_to(instance=instance, request=request) form_class = edit_handler.get_form_class() if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=instance) if form.is_valid(): form.save() messages.success( request, _("%(snippet_type)s '%(instance)s' updated.") % { 'snippet_type': capfirst(model._meta.verbose_name), 'instance': instance }, buttons=[ messages.button( reverse('wagtailsnippets:edit', args=(app_label, model_name, quote(instance.pk))), _('Edit')) ]) for fn in hooks.get_hooks('after_edit_snippet'): result = fn(request, instance) if hasattr(result, 'status_code'): return result return redirect('wagtailsnippets:list', app_label, model_name) else: messages.validation_error( request, _("The snippet could not be saved due to errors."), form) else: form = form_class(instance=instance) edit_handler = edit_handler.bind_to(form=form) context = { 'model_opts': model._meta, 'instance': instance, 'edit_handler': edit_handler, 'form': form, 'action_menu': SnippetActionMenu(request, view='edit', instance=instance), 'locale': None, 'translations': [], } if getattr(settings, 'WAGTAIL_I18N_ENABLED', False) and issubclass( model, TranslatableMixin): context.update({ 'locale': instance.locale, 'translations': [{ 'locale': translation.locale, 'url': reverse('wagtailsnippets:edit', args=[app_label, model_name, quote(translation.pk)]) } for translation in instance.get_translations().select_related( 'locale')], }) return TemplateResponse(request, 'wagtailsnippets/snippets/edit.html', context)
def edit(request, page_id): real_page_record = get_object_or_404(Page, id=page_id) latest_revision = real_page_record.get_latest_revision() content_type = real_page_record.cached_content_type page_class = real_page_record.specific_class if page_class is None: raise PageClassNotFoundError( f"The page '{real_page_record}' cannot be edited because the " f"model class used to create it ({content_type.app_label}." f"{content_type.model}) can no longer be found in the codebase. " "This usually happens as a result of switching between git " "branches without running migrations to trigger the removal of " "unused ContentTypes. To edit the page, you will need to switch " "back to a branch where the model class is still present." ) page = real_page_record.get_latest_revision_as_page() parent = page.get_parent() page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied next_url = get_valid_next_url_from_request(request) for fn in hooks.get_hooks('before_edit_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result edit_handler = page_class.get_edit_handler() edit_handler = edit_handler.bind_to(instance=page, request=request) form_class = edit_handler.get_form_class() if request.method == 'GET': if page_perms.user_has_lock(): if page.locked_at: lock_message = format_html(_("<b>Page '{}' was locked</b> by <b>you</b> on <b>{}</b>."), page.get_admin_display_title(), page.locked_at.strftime("%d %b %Y %H:%M")) else: lock_message = format_html(_("<b>Page '{}' is locked</b> by <b>you</b>."), page.get_admin_display_title()) lock_message += format_html( '<span class="buttons"><button class="button button-small button-secondary" data-locking-action="{}">{}</button></span>', reverse('wagtailadmin_pages:unlock', args=(page.id,)), _("Unlock") ) messages.warning(request, lock_message, extra_tags='lock') elif page.locked and 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 page.locked_by and page.locked_at: lock_message = format_html(_("<b>Page '{}' was locked</b> by <b>{}</b> on <b>{}</b>."), page.get_admin_display_title(), str(page.locked_by), 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(_("<b>Page '{}' is locked</b>."), page.get_admin_display_title()) if page_perms.can_unlock(): lock_message += format_html( '<span class="buttons"><button class="button button-small button-secondary" data-locking-action="{}">{}</button></span>', reverse('wagtailadmin_pages:unlock', args=(page.id,)), _("Unlock") ) messages.error(request, lock_message, extra_tags='lock') if page.current_workflow_state: workflow_state = page.current_workflow_state workflow = workflow_state.workflow workflow_tasks = workflow_state.all_tasks_with_status() task = workflow_state.current_task_state.task if ( workflow_state.status != WorkflowState.STATUS_NEEDS_CHANGES and task.specific.page_locked_for_user(page, request.user) ): # Check for revisions still undergoing moderation and warn if len(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 <b>'{}'</b> in the <b>'{}'</b> workflow."), task.name, workflow.name ) messages.error(request, mark_safe(workflow_info + " " + _("Only reviewers for this task can edit the page.")), extra_tags="lock") # Check for revisions still undergoing moderation and warn - this is for the old moderation system if latest_revision and latest_revision.submitted_for_moderation: buttons = [] if page.live: buttons.append(messages.button( reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)), _('Compare with live version') )) messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons) # Show current workflow state if set, default to last workflow state workflow_state = page.current_workflow_state or page.workflow_states.order_by('created_at').last() if workflow_state: workflow_tasks = workflow_state.all_tasks_with_status() else: workflow_tasks = [] errors_debug = None if request.method == 'POST': form = form_class(request.POST, request.FILES, instance=page, parent_page=parent) is_publishing = False is_submitting = False is_restarting_workflow = False is_reverting = False is_saving = False is_cancelling_workflow = bool(request.POST.get('action-cancel-workflow')) and workflow_state and workflow_state.user_can_cancel(request.user) if is_cancelling_workflow: workflow_state.cancel(user=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 form.is_valid() and not page_perms.page_locked(): page = form.save(commit=False) is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish() is_submitting = bool(request.POST.get('action-submit')) and page_perms.can_submit_for_moderation() is_restarting_workflow = bool(request.POST.get('action-restart-workflow')) and page_perms.can_submit_for_moderation() and workflow_state and workflow_state.user_can_cancel(request.user) is_reverting = bool(request.POST.get('revision')) is_performing_workflow_action = bool(request.POST.get('action-workflow-action')) if is_performing_workflow_action: workflow_action = request.POST['workflow-action-name'] available_actions = page.current_workflow_task.get_actions(page, 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 = form.has_changed() if is_restarting_workflow: workflow_state.cancel(user=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(page.revisions, id=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 = latest_revision else: # Save revision revision = page.save_revision( user=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 = page.go_live_at # Publish if is_publishing: for fn in hooks.get_hooks('before_publish_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result revision.publish( user=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. page = page.specific_class.objects.get(pk=page.pk) for fn in hooks.get_hooks('after_publish_page'): result = fn(request, page) if hasattr(result, 'status_code'): return result # Submit if is_submitting or is_restarting_workflow: if workflow_state and workflow_state.status == WorkflowState.STATUS_NEEDS_CHANGES: # If the workflow was in the needs changes state, resume the existing workflow on submission workflow_state.resume(request.user) else: # Otherwise start a new workflow workflow = page.get_workflow() workflow.start(page, request.user) if is_performing_workflow_action: extra_workflow_data_json = request.POST.get('workflow-action-extra-data', '{}') extra_workflow_data = json.loads(extra_workflow_data_json) page.current_workflow_task.on_action(page.current_workflow_task_state, 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"), page.get_admin_display_title() ) else: if page.live: message = _( "Page '{0}' is live and this version has been scheduled for publishing." ).format( page.get_admin_display_title() ) else: message = _( "Page '{0}' has been scheduled for publishing." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(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"), page.get_admin_display_title() ) else: message = _( "Page '{0}' has been published." ).format( page.get_admin_display_title() ) buttons = [] if page.url is not None: buttons.append(messages.button(page.url, _('View live'), new_window=True)) buttons.append(messages.button(reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit'))) messages.success(request, message, buttons=buttons) elif is_submitting: message = _( "Page '{0}' has been submitted for moderation." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:view_draft', args=(page_id,)), _('View draft'), new_window=True ), messages.button( reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit') ) ]) elif is_cancelling_workflow: message = _( "Workflow on page '{0}' has been cancelled." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:view_draft', args=(page_id,)), _('View draft'), new_window=True ), messages.button( reverse('wagtailadmin_pages:edit', args=(page_id,)), ('Edit') ) ]) elif is_restarting_workflow: message = _( "Workflow on page '{0}' has been restarted." ).format( page.get_admin_display_title() ) messages.success(request, message, buttons=[ messages.button( reverse('wagtailadmin_pages:view_draft', args=(page_id,)), _('View draft'), new_window=True ), messages.button( reverse('wagtailadmin_pages:edit', args=(page_id,)), _('Edit') ) ]) elif is_reverting: message = _( "Page '{0}' has been replaced with version from {1}." ).format( page.get_admin_display_title(), previous_revision.created_at.strftime("%d %b %Y %H:%M") ) messages.success(request, message) elif is_saving: message = _( "Page '{0}' has been updated." ).format( page.get_admin_display_title() ) messages.success(request, message) if is_saving: for fn in hooks.get_hooks('after_edit_page'): result = fn(request, 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 next_url: # redirect back to 'next' url if present return redirect(next_url) # redirect back to the explorer return redirect('wagtailadmin_explore', page.get_parent().id) else: # Just saving - remain on edit page for further edits target_url = reverse('wagtailadmin_pages:edit', args=[page.id]) if next_url: # Ensure the 'next' url is passed through again if present target_url += '?next=%s' % urlquote(next_url) return redirect(target_url) else: if page_perms.page_locked(): messages.error(request, _("The page could not be saved as it is locked")) else: messages.validation_error( request, _("The page could not be saved due to validation errors"), form ) errors_debug = ( repr(form.errors) + repr([ (name, formset.errors) for (name, formset) in form.formsets.items() if formset.errors ]) ) has_unsaved_changes = True else: form = form_class(instance=page, parent_page=parent) has_unsaved_changes = False edit_handler = edit_handler.bind_to(form=form) # Check for revisions still undergoing moderation and warn if latest_revision and latest_revision.submitted_for_moderation: buttons = [] if page.live: buttons.append(messages.button( reverse('wagtailadmin_pages:revisions_compare', args=(page.id, 'live', latest_revision.id)), _('Compare with live version') )) messages.warning(request, _("This page is currently awaiting moderation"), buttons=buttons) if page.live and page.has_unpublished_changes: # Page status needs to present the version of the page containing the correct live URL page_for_status = real_page_record.specific else: page_for_status = page return TemplateResponse(request, 'wagtailadmin/pages/edit.html', { 'page': page, 'page_for_status': page_for_status, 'content_type': content_type, 'edit_handler': edit_handler, 'errors_debug': errors_debug, 'action_menu': PageActionMenu(request, view='edit', page=page), 'preview_modes': page.preview_modes, 'form': form, 'next': next_url, 'has_unsaved_changes': has_unsaved_changes, 'page_locked': page_perms.page_locked(), 'workflow_state': workflow_state if workflow_state and workflow_state.is_active else None, 'current_task_state': page.current_workflow_task_state, 'publishing_will_cancel_workflow': workflow_tasks and getattr(settings, 'WAGTAIL_WORKFLOW_CANCEL_ON_PUBLISH', True) })