def index(request): form = SearchForm(placeholder=_("Search something")) example_form = ExampleForm() messages.success(request, _("Success message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) messages.warning(request, _("Warning message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) messages.error(request, _("Error message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) paginator = Paginator(list(range(100)), 10) page = paginator.page(2) user = User(email='*****@*****.**') return render(request, 'wagtailstyleguide/base.html', { 'search_form': form, 'example_form': example_form, 'example_page': page, 'user': user, })
def resend(request): to_email = request.session.get('to_email') host_link = request.session.get('host_link') username = request.session.get('username') if username is not None: user = User.objects.get(username=username) if user is not None: # if user account is already activated if user.is_active: messages.error(request, 'Your account is already activated!') return redirect('members:account_home') # if user account is not activated yet and user's inactive profile remains in db else: if send_validation_email(request, user, to_email, 'register'): # reload session request.session['host_link'] = host_link return render(request, 'activate_account_popup.html', {'host_link': host_link}) # if user's inactive profile is removed from db else: print('in 404') messages.error( request, 'Sorry, your registration has expired. Please sign up again') return redirect(reverse_lazy('members:signup')) else: messages.warning(request, "Invalid action") return render(request, 'activate_account_popup.html', {'host_link': host_link})
def index(request): form = SearchForm(placeholder=_("Search something")) example_form = ExampleForm() messages.success(request, _("Success message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) messages.warning(request, _("Warning message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) messages.error(request, _("Error message"), buttons=[ messages.button('', _('View live')), messages.button('', _('Edit')) ]) paginator = Paginator(list(range(100)), 10) page = paginator.page(2) return TemplateResponse(request, 'wagtailstyleguide/base.html', { 'search_form': form, 'example_form': example_form, 'example_page': page, })
def newsletter_form_page_check_sendy_api(request, page): if isinstance(page, NewsletterFormPage): if not page.sendy_list_id: message = _( 'There is no sendy_list_id set for page "%s". ' "Therefore newsletter subscription will not work." % page ) messages.warning(request, message) elif not settings.DEBUG: sendy_response = None try: sendy_response = sendy_api.subscriber_count(page.sendy_list_id) # Sendy will return an integer if the given list_id exists int(sendy_response) except ( ConnectionError, NewConnectionError, MaxRetryError, ValueError, ) as e: message = ( _( "There was a problem talking to Sendy API: %s. " "Please check the sendy_list_id and try again." ) % sendy_response if sendy_response else e ) messages.warning(request, message)
def dispatch(self, request, *args, **kwargs): self.object = self.get_object() profile = self.object.userprofile self.is_approval = profile.assignment_status in ( UserProfile.STATUS_CREATED, UserProfile.STATUS_AWAITING_APPROVAL, ) if ( settings.FEATURE_FLAGS['ENFORCE_STAFF_SSO_ON'] and self.is_approval and request.method == 'GET' ): # Warn the current user that this is an 'approval' message_text = ( "This user is awaiting approval and will be automatically " "notified via email if added to a group that grants access " "to the Wagtail CMS." ) if profile.self_assigned_group: # Preselect the user-selcted group in the form self.initial['groups'] = [profile.self_assigned_group.id] # Also mention this to the current user message_text += ( " They requested to be added to the '{}' group, so this " "has been preselected for you under the 'Roles' tab." ).format(profile.self_assigned_group.name) messages.warning(request, message_text) return super().dispatch(request, *args, **kwargs)
def revisions_revert(request, page_id, revision_id): page = get_object_or_404(Page, id=page_id).specific page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied revision = get_object_or_404(page.revisions, id=revision_id) revision_page = revision.as_page_object() content_type = ContentType.objects.get_for_model(page) page_class = content_type.model_class() edit_handler = page_class.get_edit_handler() edit_handler = edit_handler.bind_to(instance=revision_page, request=request) form_class = edit_handler.get_form_class() form = form_class(instance=revision_page) edit_handler = edit_handler.bind_to(form=form) user_avatar = render_to_string("wagtailadmin/shared/user_avatar.html", {"user": revision.user}) messages.warning( request, mark_safe( _("You are viewing a previous version of this page from <b>%(created_at)s</b> by %(user)s" ) % { "created_at": revision.created_at.strftime("%d %b %Y %H:%M"), "user": user_avatar, }), ) return TemplateResponse( request, "wagtailadmin/pages/edit.html", { "page": page, "revision": revision, "is_revision": True, "content_type": content_type, "edit_handler": edit_handler, "errors_debug": None, "action_menu": PageActionMenu(request, view="revisions_revert", page=page), "preview_modes": page.preview_modes, "form": form, # Used in unit tests }, )
def revisions_revert(request, page_id, revision_id): page = get_object_or_404(Page, id=page_id).specific page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied revision = get_object_or_404(page.revisions, id=revision_id) revision_page = revision.as_page_object() content_type = ContentType.objects.get_for_model(page) page_class = content_type.model_class() edit_handler = page_class.get_edit_handler() edit_handler = edit_handler.bind_to(instance=revision_page, request=request) form_class = edit_handler.get_form_class() form = form_class(instance=revision_page) edit_handler = edit_handler.bind_to(form=form) user_avatar = render_to_string('wagtailadmin/shared/user_avatar.html', {'user': revision.user}) messages.warning( request, mark_safe( _("You are viewing a previous version of this page from <b>%(created_at)s</b> by %(user)s" ) % { 'created_at': revision.created_at.strftime("%d %b %Y %H:%M"), 'user': user_avatar, })) return TemplateResponse( request, 'wagtailadmin/pages/edit.html', { 'page': page, 'revision': revision, 'is_revision': True, 'content_type': content_type, 'edit_handler': edit_handler, 'errors_debug': None, 'action_menu': PageActionMenu(request, view='revisions_revert', page=page), 'preview_modes': page.preview_modes, 'form': form, # Used in unit tests })
def run_scan(request): site = Site.find_for_request(request) celery_status = get_celery_worker_status() if 'ERROR' not in celery_status: broken_link_scan(site) else: messages.warning( request, _('No celery workers are running, the scan was not conducted.')) return redirect('wagtaillinkchecker')
def add_legacy_moderation_warning(self): # Check for revisions still undergoing moderation and warn - this is for the old moderation system if self.latest_revision and self.latest_revision.submitted_for_moderation: buttons = [] if self.page.live: buttons.append(self.get_compare_with_live_message_button()) messages.warning(self.request, _("This page is currently awaiting moderation"), buttons=buttons)
def get(self, *args, **kwargs): new_mails = self.instance.get_new_mail() if new_mails: messages.success( self.request, f"Mail updated for {self.instance}: {len(new_mails)} new mails" ) else: messages.warning( self.request, f"Mail updated for {self.instance}: no new mails") return redirect(self.index_url)
def get(self, request): if self.lock: lock_message = self.lock.get_message(self.request.user) if lock_message: if isinstance(self.lock, BasicLock) and self.page_perms.can_unlock(): lock_message = format_html( '{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>', lock_message, reverse("wagtailadmin_pages:unlock", args=(self.page.id, )), _("Unlock"), ) if (isinstance(self.lock, ScheduledForPublishLock) and self.page_perms.can_unschedule()): scheduled_revision = self.page.revisions.defer().get( approved_go_live_at__isnull=False) lock_message = format_html( '{} <span class="buttons"><button type="button" class="button button-small button-secondary" data-action-lock-unlock data-url="{}">{}</button></span>', lock_message, reverse( "wagtailadmin_pages:revisions_unschedule", args=[self.page.id, scheduled_revision.pk], ), _("Cancel scheduled publish"), ) if self.locked_for_user: messages.error(self.request, lock_message, extra_tags="lock") else: messages.warning(self.request, lock_message, extra_tags="lock") self.form = self.form_class( instance=self.page, subscription=self.subscription, parent_page=self.parent, for_user=self.request.user, ) self.has_unsaved_changes = False self.add_legacy_moderation_warning() self.page_for_status = self.get_page_for_status() return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs): if '_refund-error' in request.POST: # Refund error, add error message and redirect to change view. msg = _("There was an error while trying to refund order.") messages.error(request, msg) if '_refund-success' in request.POST: # Refund success, add success message and redirect to change view. failed = int(request.POST['_refund-success']) if failed: msg = _("The Order “{}” was only partially refunded.") messages.warning(request, msg.format(self.instance)) else: msg = _("The Order “{}” was successfully refunded.") messages.success(request, msg.format(self.instance)) return redirect(self.edit_url)
def get_redirect_url(self, *args, **kwargs): index = models.ScrutinIndex.objects.last() if not index: root = models.SitePage.objects.first() if not root: messages.error( self.request, "Impossible de trouver la racine de votre site.", ) return reverse('wagtailadmin_home') messages.warning( self.request, "Impossible de trouver une page d'index des formulaires. " "Veillez d'abord en ajouter une.", ) return reverse('wagtailadmin_pages:add_subpage', args=(root.id, )) return reverse('wagtailadmin_pages:add_subpage', args=(index.id, ))
def import_page(request): """ View for the import page. """ if request.method == 'POST': form = forms.ImportPage(request.POST, request.FILES) if form.is_valid(): # Read fields on the submitted form. form_file = form.cleaned_data['file'] form_parentpage = form.cleaned_data['parent_page'] # Import pages and get the response. num_uploaded, num_failed, response = importing.import_page(form_file, form_parentpage) # Show messages depending on the response. if not num_failed: # All pages are imported. messages.success( request, ungettext("Imported %(count)s page.", "Imported %(count)s pages.", num_uploaded) % {'count': num_uploaded} ) elif not num_uploaded: # None of the pages are imported. messages.error( request, ungettext("Failed to import %(count)s page. %(reason)s", "Failed to import %(count)s pages. %(reason)s", num_failed) % {'count': num_failed, 'reason': response} ) else: # Some pages are imported and some failed. messages.warning( request, ungettext("Failed to import %(failed)s out of %(total)s page. %(reason)s", "Failed to import %(failed)s out of %(total)s pages. %(reason)s", num_failed + num_uploaded) % {'failed': num_failed, 'total': num_failed + num_uploaded, 'reason': response} ) # Redirect client to the parent page view on admin. return redirect('wagtailadmin_explore', form_parentpage.pk) else: form = forms.ImportPage() # Redirect client to form. return render(request, 'wagtailimportexport/import-page.html', { 'form': form, })
def custom_wagtail_page_delete(request, page_id): """ Currently, ProtectedError exception is not caught in Wagtail admin. This workaround shows warning to the user if the page model like Fund, Round can not be deleted instead of raising 500. More details at https://github.com/wagtail/wagtail/issues/1602 Once the issue is fixed in Wagtail core, we can remove this workaround. """ try: return delete(request, page_id) except ProtectedError as e: protected_details = ", ".join([str(obj) for obj in e.protected_objects]) page = get_object_or_404(Page, id=page_id).specific parent_id = page.get_parent().id messages.warning(request, _("Page '{0}' can't be deleted because is in use in '{1}'.").format( page.get_admin_display_title(), protected_details )) return redirect('wagtailadmin_explore', parent_id)
def disable_delete(request, page): """Disable deleting of speakers/events We don't want it because it breaks urls and connections between speakers and events. We disable it only during POST request (so in the final stage of deleting). This means delete confirmation page is displayed. From there user can alternatively unpublish the page. """ if ( request.user.username != "admin" and page.specific_class in [Speaker, Event] and request.method == "POST" ): messages.warning( request, _("Page '{0}' can not be deleted. You can only unpublish it.").format( page.get_admin_display_title() ), ) return redirect("wagtailadmin_pages:delete", page.pk)
def index(request): form = SearchForm(placeholder=_("Search something")) example_form = ExampleForm() messages.success( request, _("Success message"), buttons=[ messages.button("", _("View live")), messages.button("", _("Edit")) ], ) messages.warning( request, _("Warning message"), buttons=[ messages.button("", _("View live")), messages.button("", _("Edit")) ], ) messages.error( request, _("Error message"), buttons=[ messages.button("", _("View live")), messages.button("", _("Edit")) ], ) paginator = Paginator(list(range(100)), 10) page = paginator.page(2) return TemplateResponse( request, "wagtailstyleguide/base.html", { "search_form": form, "example_form": example_form, "example_page": page, }, )
def revisions_revert(request, page_id, revision_id): page = get_object_or_404(Page, id=page_id).specific page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied revision = get_object_or_404(page.revisions, id=revision_id) revision_page = revision.as_page_object() content_type = ContentType.objects.get_for_model(page) page_class = content_type.model_class() edit_handler = page_class.get_edit_handler() edit_handler = edit_handler.bind_to(instance=revision_page, request=request) form_class = edit_handler.get_form_class() form = form_class(instance=revision_page) edit_handler = edit_handler.bind_to(form=form) user_avatar = render_to_string('wagtailadmin/shared/user_avatar.html', {'user': revision.user}) messages.warning(request, mark_safe( _("You are viewing a previous revision of this page from <b>%(created_at)s</b> by %(user)s") % { 'created_at': revision.created_at.strftime("%d %b %Y %H:%M"), 'user': user_avatar, } )) return render(request, 'wagtailadmin/pages/edit.html', { 'page': page, 'revision': revision, 'is_revision': True, 'content_type': content_type, 'edit_handler': edit_handler, 'errors_debug': None, 'action_menu': PageActionMenu(request, view='revisions_revert', page=page), 'preview_modes': page.preview_modes, 'form': form, # Used in unit tests })
def my_hook_function(request, page): conf = apps.get_app_config('wagtail_cloudfront_invalidate') if not conf.enabled: return try: invalidate(conf.AWS_ACCESS_KEY_ID, conf.AWS_SECRET_ACCESS_KEY, conf.CLOUDFRONT_DISTRIBUTION_ID, items=[ page.get_url(), ]) except ParamValidationError: messages.warning( request, _('Cloudfront Invalidation Error. Check that your AWS access key, secret key and Cloudfront distribution ID are set.' )) except Exception as e: messages.warning(request, e.__str__())
def dry_run(self): """Crible les lignes en vue de l'affichage de la confirmation.""" ok, warn, ko = self.crible_data() if ok and not warn and not ko: messages.success( self.request, "L'import est valide et peut être poursuivi.", ) elif warn and not ko: messages.warning( self.request, "L'import est valide mais demande une attention " "particulière avant d'être poursuivi.", ) elif ko: messages.error( self.request, "L'import ne peut être poursuivi du fait d'erreurs.", buttons=[ messages.button(reverse('import:index'), "Re-tenter un import"), ], ) return ok, warn, ko
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) })
def get(self, request): if self.page_perms.user_has_lock(): if self.page.locked_at: lock_message = format_html( _("<b>Page '{}' was locked</b> by <b>you</b> on <b>{}</b>." ), self.page.get_admin_display_title(), self.page.locked_at.strftime("%d %b %Y %H:%M")) else: lock_message = format_html( _("<b>Page '{}' is locked</b> by <b>you</b>."), self.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=(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( _("<b>Page '{}' was locked</b> by <b>{}</b> on <b>{}</b>." ), 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(_("<b>Page '{}' is locked</b>."), self.page.get_admin_display_title()) if self.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=(self.page.id, )), _("Unlock")) messages.error(self.request, lock_message, 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 <b>'{}'</b> in the <b>'{}'</b> 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() return self.render_to_response(self.get_context_data())
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 edit_translation(request, translation, instance): if isinstance(instance, Page): # Page # Note: Edit permission is already checked by the edit page view page_perms = instance.permissions_for_user(request.user) is_live = instance.live is_locked = instance.locked if instance.live_revision: last_published_at = instance.live_revision.created_at last_published_by = instance.live_revision.user else: last_published_at = instance.last_published_at last_published_by = None if instance.live: live_url = instance.full_url else: live_url = None can_publish = page_perms.can_publish() can_unpublish = page_perms.can_unpublish() can_lock = page_perms.can_lock() can_unlock = page_perms.can_unlock() can_delete = page_perms.can_delete() else: # Snippet # Note: Edit permission is already checked by the edit snippet view is_live = True is_locked = False last_published_at = None last_published_by = None live_url = None can_publish = True can_unpublish = False can_lock = False can_unlock = False can_delete = request.user.has_perm( get_permission_name("delete", instance.__class__) ) source_instance = translation.source.get_source_instance() if request.method == "POST": if request.POST.get("action") == "publish": if isinstance(instance, Page): if not page_perms.can_publish(): raise PermissionDenied try: translation.save_target(user=request.user, publish=True) except ValidationError: messages.error( request, _( "New validation errors were found when publishing '{object}' in {locale}. Please fix them or click publish again to ignore these translations for now." ).format( object=str(instance), locale=translation.target_locale.get_display_name(), ), ) else: # Refresh instance to title in success message is up to date instance.refresh_from_db() string_segments = translation.source.stringsegment_set.all().order_by( "order" ) string_translations = string_segments.get_translations( translation.target_locale ) # Using annotate_translation as this ignores errors by default (so both errors and missing segments treated the same) if ( string_segments.annotate_translation(translation.target_locale) .filter(translation__isnull=True) .exists() ): # One or more strings had an error messages.warning( request, _( "Published '{object}' in {locale} with missing translations - see below." ).format( object=str(instance), locale=translation.target_locale.get_display_name(), ), ) else: messages.success( request, _("Published '{object}' in {locale}.").format( object=str(instance), locale=translation.target_locale.get_display_name(), ), ) return redirect(request.path) string_segments = translation.source.stringsegment_set.all().order_by("order") string_translations = string_segments.get_translations(translation.target_locale) overridable_segments = translation.source.overridablesegment_set.all().order_by( "order" ) segment_overrides = overridable_segments.get_overrides(translation.target_locale) related_object_segments = ( translation.source.relatedobjectsegment_set.all().order_by("order") ) tab_helper = TabHelper(source_instance) breadcrumb = [] title_segment_id = None if isinstance(instance, Page): # find the closest common ancestor of the pages that this user has direct explore permission # (i.e. add/edit/publish/lock) over; this will be the root of the breadcrumb cca = get_explorable_root_page(request.user) if cca: breadcrumb = [ { "id": page.id, "isRoot": page.is_root(), "title": page.title, "exploreUrl": reverse("wagtailadmin_explore_root") if page.is_root() else reverse("wagtailadmin_explore", args=[page.id]), } for page in instance.get_ancestors(inclusive=False).descendant_of( cca, inclusive=True ) ] # Set to the ID of a string segment that represents the title. # If this segment has a translation, the title will be replaced with that translation. try: title_segment_id = string_segments.get(context__path="title").id except StringSegment.DoesNotExist: pass machine_translator = None translator = get_machine_translator() if translator and translator.can_translate( translation.source.locale, translation.target_locale ): machine_translator = { "name": translator.display_name, "url": reverse("wagtail_localize:machine_translate", args=[translation.id]), } segments = [] for segment in string_segments: try: location_info = get_segment_location_info( source_instance, tab_helper, segment.context.path, segment.context.get_field_path(source_instance), ) except FieldHasNoEditPanelError: continue segments.append( { "type": "string", "id": segment.id, "contentPath": segment.context.path, "source": segment.string.data, "location": location_info, "editUrl": reverse( "wagtail_localize:edit_string_translation", kwargs={ "translation_id": translation.id, "string_segment_id": segment.id, }, ), "order": segment.order, } ) for segment in overridable_segments: try: location_info = get_segment_location_info( source_instance, tab_helper, segment.context.path, segment.context.get_field_path(source_instance), widget=True, ) except FieldHasNoEditPanelError: continue segments.append( { "type": "synchronised_value", "id": segment.id, "contentPath": segment.context.path, "location": location_info, "value": segment.data, "editUrl": reverse( "wagtail_localize:edit_override", kwargs={ "translation_id": translation.id, "overridable_segment_id": segment.id, }, ), "order": segment.order, } ) def get_source_object_info(segment): instance = segment.get_source_instance() if isinstance(instance, Page): return { "title": str(instance), "isLive": instance.live, "liveUrl": instance.full_url, "editUrl": reverse("wagtailadmin_pages:edit", args=[instance.id]), "createTranslationRequestUrl": reverse( "wagtail_localize:submit_page_translation", args=[instance.id] ), } else: return { "title": str(instance), "isLive": True, "editUrl": reverse( "wagtailsnippets:edit", args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id), ], ), "createTranslationRequestUrl": reverse( "wagtail_localize:submit_snippet_translation", args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id), ], ), } def get_dest_object_info(segment): instance = segment.object.get_instance_or_none(translation.target_locale) if not instance: return if isinstance(instance, Page): return { "title": str(instance), "isLive": instance.live, "liveUrl": instance.full_url, "editUrl": reverse("wagtailadmin_pages:edit", args=[instance.id]), } else: return { "title": str(instance), "isLive": True, "editUrl": reverse( "wagtailsnippets:edit", args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id), ], ), } def get_translation_progress(segment, locale): try: translation = Translation.objects.get( source__object_id=segment.object_id, target_locale=locale, enabled=True ) except Translation.DoesNotExist: return None total_segments, translated_segments = translation.get_progress() return { "totalSegments": total_segments, "translatedSegments": translated_segments, } for segment in related_object_segments: try: location_info = get_segment_location_info( source_instance, tab_helper, segment.context.path, segment.context.get_field_path(source_instance), ) except FieldHasNoEditPanelError: continue segments.append( { "type": "related_object", "id": segment.id, "contentPath": segment.context.path, "location": location_info, "order": segment.order, "source": get_source_object_info(segment), "dest": get_dest_object_info(segment), "translationProgress": get_translation_progress( segment, translation.target_locale ), } ) # Order segments by how they appear in the content panels # segment['location']['order'] is the content panel ordering # segment['order'] is the model field ordering # User's expect segments to follow the panel ordering as that's the ordering # that is used in the page editor of the source page. However, segments that # come from the same streamfield/inline panel are given the same value for # panel ordering, so we need to order by model field ordering as well (all # segments have a unique value for model field ordering) segments.sort(key=lambda segment: (segment["location"]["order"], segment["order"])) # Display a warning to the user if the schema of the source model has been updated since the source was last updated if translation.source.schema_out_of_date(): messages.warning( request, _( "The data model for '{model_name}' has been changed since the last translation sync. " "If any new fields have been added recently, these may not be visible until the next translation sync." ).format(model_name=capfirst(source_instance._meta.verbose_name)), ) return render( request, "wagtail_localize/admin/edit_translation.html", { "translation": translation, # These props are passed directly to the TranslationEditor react component "props": json.dumps( { "adminBaseUrl": reverse("wagtailadmin_home"), "object": { "title": str(instance), "titleSegmentId": title_segment_id, "isLive": is_live, "isLocked": is_locked, "lastPublishedDate": last_published_at.strftime(DATE_FORMAT) if last_published_at is not None else None, "lastPublishedBy": UserSerializer(last_published_by).data if last_published_by is not None else None, "liveUrl": live_url, }, "breadcrumb": breadcrumb, "tabs": tab_helper.tabs_with_slugs, "sourceLocale": { "code": translation.source.locale.language_code, "displayName": translation.source.locale.get_display_name(), }, "locale": { "code": translation.target_locale.language_code, "displayName": translation.target_locale.get_display_name(), }, "translations": [ { "title": str(translated_instance), "locale": { "code": translated_instance.locale.language_code, "displayName": translated_instance.locale.get_display_name(), }, "editUrl": reverse( "wagtailadmin_pages:edit", args=[translated_instance.id] ) if isinstance(translated_instance, Page) else reverse( "wagtailsnippets:edit", args=[ translated_instance._meta.app_label, translated_instance._meta.model_name, quote(translated_instance.id), ], ), } for translated_instance in instance.get_translations().select_related( "locale" ) ], "perms": { "canPublish": can_publish, "canUnpublish": can_unpublish, "canLock": can_lock, "canUnlock": can_unlock, "canDelete": can_delete, }, "links": { "downloadPofile": reverse( "wagtail_localize:download_pofile", args=[translation.id] ), "uploadPofile": reverse( "wagtail_localize:upload_pofile", args=[translation.id] ), "unpublishUrl": reverse( "wagtailadmin_pages:unpublish", args=[instance.id] ) if isinstance(instance, Page) else None, "lockUrl": reverse( "wagtailadmin_pages:lock", args=[instance.id] ) if isinstance(instance, Page) else None, "unlockUrl": reverse( "wagtailadmin_pages:unlock", args=[instance.id] ) if isinstance(instance, Page) else None, "deleteUrl": reverse( "wagtailadmin_pages:delete", args=[instance.id] ) if isinstance(instance, Page) else reverse( "wagtailsnippets:delete", args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.pk), ], ), "stopTranslationUrl": reverse( "wagtail_localize:stop_translation", args=[translation.id] ), }, "previewModes": [ { "mode": mode, "label": label, "url": reverse( "wagtail_localize:preview_translation", args=[translation.id], ) if mode == instance.default_preview_mode else reverse( "wagtail_localize:preview_translation", args=[translation.id, mode], ), } for mode, label in ( instance.preview_modes if isinstance(instance, Page) else [] ) ], "machineTranslator": machine_translator, "segments": segments, # We serialize the translation data using Django REST Framework. # This gives us a consistent representation with the APIs so we # can dynamically update translations in the view. "initialStringTranslations": StringTranslationSerializer( string_translations, many=True, context={"translation_source": translation.source}, ).data, "initialOverrides": SegmentOverrideSerializer( segment_overrides, many=True, context={"translation_source": translation.source}, ).data, }, cls=DjangoJSONEncoder, ), }, )
def get(self, request, *args, **kwargs): if self.instance.is_fully_booked: messages.warning(request, _('This course is fully booked.')) return super().get(request, *args, **kwargs)
def _add_warning_message(self): messages.warning(self.request, self.get_warning_message())
def machine_translate(request, translation_id): translation = get_object_or_404(Translation, id=translation_id) instance = translation.get_target_instance() if not user_can_edit_instance(request.user, instance): raise PermissionDenied translator = get_machine_translator() if translator is None: raise Http404 if not translator.can_translate(translation.source.locale, translation.target_locale): raise Http404 # Get segments segments = defaultdict(list) for string_segment in translation.source.stringsegment_set.all( ).select_related("context", "string"): segment = StringSegmentValue( string_segment.context.path, string_segment.string.as_value()).with_order(string_segment.order) if string_segment.attrs: segment.attrs = json.loads(string_segment.attrs) # Don't translate if there already is a translation if StringTranslation.objects.filter( translation_of_id=string_segment.string_id, locale=translation.target_locale, context_id=string_segment.context_id, ).exists(): continue segments[segment.string].append( (string_segment.string_id, string_segment.context_id)) if segments: translations = translator.translate(translation.source.locale, translation.target_locale, segments.keys()) with transaction.atomic(): for string, contexts in segments.items(): for string_id, context_id in contexts: StringTranslation.objects.get_or_create( translation_of_id=string_id, locale=translation.target_locale, context_id=context_id, defaults={ 'data': translations[string].data, 'translation_type': StringTranslation.TRANSLATION_TYPE_MACHINE, 'tool_name': translator.display_name, 'last_translated_by': request.user, 'has_error': False, 'field_error': "", }) messages.success( request, _("Successfully translated with {}.").format( translator.display_name)) else: messages.warning(request, _("There isn't anything left to translate.")) # Work out where to redirect to next_url = get_valid_next_url_from_request(request) if not next_url: # Note: You should always provide a next URL when using this view! next_url = reverse('wagtailadmin_home') return redirect(next_url)
def edit_translation(request, translation, instance): if isinstance(instance, Page): # Page # Note: Edit permission is already checked by the edit page view page_perms = instance.permissions_for_user(request.user) is_live = instance.live is_locked = instance.locked if instance.live_revision: last_published_at = instance.live_revision.created_at last_published_by = instance.live_revision.user else: last_published_at = instance.last_published_at last_published_by = None if instance.live: live_url = instance.full_url else: live_url = None can_publish = page_perms.can_publish() can_unpublish = page_perms.can_unpublish() can_lock = page_perms.can_lock() can_unlock = page_perms.can_unlock() can_delete = page_perms.can_delete() else: # Snippet # Note: Edit permission is already checked by the edit snippet view is_live = True is_locked = False last_published_at = None last_published_by = None live_url = None can_publish = True can_unpublish = False can_lock = False can_unlock = False can_delete = request.user.has_perm( get_permission_name('delete', instance.__class__)) source_instance = translation.source.get_source_instance() if request.method == 'POST': if request.POST.get('action') == 'publish': if isinstance(instance, Page): if not page_perms.can_publish(): raise PermissionDenied try: translation.save_target(user=request.user, publish=True) except ValidationError: messages.error( request, _("New validation errors were found when publishing '{object}' in {locale}. Please fix them or click publish again to ignore these translations for now." ).format( object=str(instance), locale=translation.target_locale.get_display_name())) else: # Refresh instance to title in success message is up to date instance.refresh_from_db() string_segments = translation.source.stringsegment_set.all( ).order_by('order') string_translations = string_segments.get_translations( translation.target_locale) # Using annotate_translation as this ignores errors by default (so both errors and missing segments treated the same) if string_segments.annotate_translation( translation.target_locale).filter( translation__isnull=True).exists(): # One or more strings had an error messages.warning( request, _("Published '{object}' in {locale} with missing translations - see below." ).format(object=str(instance), locale=translation.target_locale. get_display_name())) else: messages.success( request, _("Published '{object}' in {locale}.").format( object=str(instance), locale=translation.target_locale.get_display_name( ))) return redirect(request.path) string_segments = translation.source.stringsegment_set.all().order_by( 'order') string_translations = string_segments.get_translations( translation.target_locale) overridable_segments = translation.source.overridablesegment_set.all( ).order_by('order') segment_overrides = overridable_segments.get_overrides( translation.target_locale) related_object_segments = translation.source.relatedobjectsegment_set.all( ).order_by('order') tab_helper = TabHelper(source_instance) breadcrumb = [] title_segment_id = None if isinstance(instance, Page): # find the closest common ancestor of the pages that this user has direct explore permission # (i.e. add/edit/publish/lock) over; this will be the root of the breadcrumb cca = get_explorable_root_page(request.user) if cca: breadcrumb = [{ 'id': page.id, 'isRoot': page.is_root(), 'title': page.title, 'exploreUrl': reverse('wagtailadmin_explore_root') if page.is_root() else reverse('wagtailadmin_explore', args=[page.id]), } for page in instance.get_ancestors( inclusive=False).descendant_of(cca, inclusive=True)] # Set to the ID of a string segment that represents the title. # If this segment has a translation, the title will be replaced with that translation. try: title_segment_id = string_segments.get(context__path='title').id except StringSegment.DoesNotExist: pass machine_translator = None translator = get_machine_translator() if translator and translator.can_translate(translation.source.locale, translation.target_locale): machine_translator = { 'name': translator.display_name, 'url': reverse('wagtail_localize:machine_translate', args=[translation.id]), } string_segment_data = [{ 'type': 'string', 'id': segment.id, 'contentPath': segment.context.path, 'source': segment.string.data, 'location': get_segment_location_info(source_instance, tab_helper, segment.context.path), 'editUrl': reverse('wagtail_localize:edit_string_translation', kwargs={ 'translation_id': translation.id, 'string_segment_id': segment.id }), 'order': segment.order, } for segment in string_segments] syncronised_value_segment_data = [{ 'type': 'synchronised_value', 'id': segment.id, 'contentPath': segment.context.path, 'location': get_segment_location_info(source_instance, tab_helper, segment.context.path, widget=True), 'value': segment.data, 'editUrl': reverse('wagtail_localize:edit_override', kwargs={ 'translation_id': translation.id, 'overridable_segment_id': segment.id }), 'order': segment.order, } for segment in overridable_segments] def get_source_object_info(segment): instance = segment.get_source_instance() if isinstance(instance, Page): return { 'title': str(instance), 'isLive': instance.live, 'liveUrl': instance.full_url, 'editUrl': reverse('wagtailadmin_pages:edit', args=[instance.id]), 'createTranslationRequestUrl': reverse('wagtail_localize:submit_page_translation', args=[instance.id]), } else: return { 'title': str(instance), 'isLive': True, 'editUrl': reverse('wagtailsnippets:edit', args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id) ]), 'createTranslationRequestUrl': reverse('wagtail_localize:submit_snippet_translation', args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id) ]), } def get_dest_object_info(segment): instance = segment.object.get_instance_or_none( translation.target_locale) if not instance: return if isinstance(instance, Page): return { 'title': str(instance), 'isLive': instance.live, 'liveUrl': instance.full_url, 'editUrl': reverse('wagtailadmin_pages:edit', args=[instance.id]), } else: return { 'title': str(instance), 'isLive': True, 'editUrl': reverse('wagtailsnippets:edit', args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.id) ]), } def get_translation_progress(segment, locale): try: translation = Translation.objects.get( source__object_id=segment.object_id, target_locale=locale, enabled=True) except Translation.DoesNotExist: return None total_segments, translated_segments = translation.get_progress() return { 'totalSegments': total_segments, 'translatedSegments': translated_segments, } related_object_segment_data = [{ 'type': 'related_object', 'id': segment.id, 'contentPath': segment.context.path, 'location': get_segment_location_info(source_instance, tab_helper, segment.context.path), 'order': segment.order, 'source': get_source_object_info(segment), 'dest': get_dest_object_info(segment), 'translationProgress': get_translation_progress(segment, translation.target_locale), } for segment in related_object_segments] segments = string_segment_data + syncronised_value_segment_data + related_object_segment_data segments.sort(key=lambda segment: segment['order']) return render( request, 'wagtail_localize/admin/edit_translation.html', { # These props are passed directly to the TranslationEditor react component 'props': json.dumps( { 'object': { 'title': str(instance), 'titleSegmentId': title_segment_id, 'isLive': is_live, 'isLocked': is_locked, 'lastPublishedDate': last_published_at.strftime(DATE_FORMAT) if last_published_at is not None else None, 'lastPublishedBy': UserSerializer(last_published_by).data if last_published_by is not None else None, 'liveUrl': live_url, }, 'breadcrumb': breadcrumb, 'tabs': tab_helper.tabs_with_slugs, 'sourceLocale': { 'code': translation.source.locale.language_code, 'displayName': translation.source.locale.get_display_name(), }, 'locale': { 'code': translation.target_locale.language_code, 'displayName': translation.target_locale.get_display_name(), }, 'translations': [{ 'title': str(translated_instance), 'locale': { 'code': translated_instance.locale.language_code, 'displayName': translated_instance.locale.get_display_name(), }, 'editUrl': reverse('wagtailadmin_pages:edit', args=[translated_instance.id]) if isinstance( translated_instance, Page) else reverse('wagtailsnippets:edit', args=[ translated_instance._meta.app_label, translated_instance._meta.model_name, quote(translated_instance.id) ]), } for translated_instance in instance.get_translations(). select_related('locale')], 'perms': { 'canPublish': can_publish, 'canUnpublish': can_unpublish, 'canLock': can_lock, 'canUnlock': can_unlock, 'canDelete': can_delete, }, 'links': { 'downloadPofile': reverse('wagtail_localize:download_pofile', args=[translation.id]), 'uploadPofile': reverse('wagtail_localize:upload_pofile', args=[translation.id]), 'unpublishUrl': reverse('wagtailadmin_pages:unpublish', args=[instance.id]) if isinstance( instance, Page) else None, 'lockUrl': reverse('wagtailadmin_pages:lock', args=[instance.id]) if isinstance(instance, Page) else None, 'unlockUrl': reverse('wagtailadmin_pages:unlock', args=[instance.id]) if isinstance( instance, Page) else None, 'deleteUrl': reverse('wagtailadmin_pages:delete', args=[instance.id]) if isinstance( instance, Page) else reverse( 'wagtailsnippets:delete', args=[ instance._meta.app_label, instance._meta.model_name, quote(instance.pk) ]), 'stopTranslationUrl': reverse('wagtail_localize:stop_translation', args=[translation.id]), }, 'previewModes': [{ 'mode': mode, 'label': label, 'url': reverse('wagtail_localize:preview_translation', args=[translation.id]) if mode == instance.default_preview_mode else reverse( 'wagtail_localize:preview_translation', args=[translation.id, mode]), } for mode, label in (instance.preview_modes if isinstance( instance, Page) else [])], 'machineTranslator': machine_translator, 'segments': segments, # We serialize the translation data using Django REST Framework. # This gives us a consistent representation with the APIs so we # can dynamically update translations in the view. 'initialStringTranslations': StringTranslationSerializer(string_translations, many=True, context={ 'translation_source': translation.source }).data, 'initialOverrides': SegmentOverrideSerializer(segment_overrides, many=True, context={ 'translation_source': translation.source }).data, }, cls=DjangoJSONEncoder) })
def form_valid(self, form): response = super().form_valid(form) # Create the student account student_group = Group.objects.get(name="Students") student_user = User.objects.create_user( username=form.cleaned_data["username"], email=form.cleaned_data["email"], first_name=form.cleaned_data["first_name"], last_name=form.cleaned_data["last_name"], ) # Add the student group student_user.groups.add(student_group) student_user.set_unusable_password() student_user.save() # return here if we aren't creating a page for the student if not form.cleaned_data["create_student_page"]: messages.success( self.request, f"The Student account for {student_user} has been created.", ) return response # Is there a student index page we can create a student page under? student_index = StudentIndexPage.objects.first() if not student_index: messages.warning( self.request, f"Failed to create a Student Page matching for the new user: {student_user}, " "a Parent Student Index Page is required.", ) logger.info( "There is not parent Student Index page to create a Student Page under, " f"so one has not been created for user: {student_user}") return response # If a student page already exist for this user, we don't want to create one. student_page = StudentPage.objects.filter( first_name=form.cleaned_data["first_name"], last_name=form.cleaned_data["last_name"], ).exists() if student_page: messages.success( self.request, f"The Student account for {student_user} has been created.", ) messages.warning( self.request, f"Failed to create a Student Page matching for the new user: {student_user}, " "a Student Page already already exists", ) logger.info( "A Student User has been created, but a StudentPage matching " f"the users name already exists: {student_page}, so one has not been created" ) else: student_index.add_child(instance=StudentPage( first_name=form.cleaned_data["first_name"], last_name=form.cleaned_data["last_name"], title= f"{form.cleaned_data['first_name']} {form.cleaned_data['last_name']}", student_user_image_collection=form. cleaned_data["student_user_image_collection"], student_user_account=student_user, live=True, )) # Place the page in draft mode # StudentPage.save() handles the creation of the group and permissions for the student student_page = StudentPage.objects.get( student_user_account=student_user) student_page.save_revision() student_page.unpublish() # Generate a password reset link to be emailed to the user. password_reset_url = self.request.build_absolute_uri( get_set_password_url(student_user)) # Notify the user of the account. email_subject = _("Your Student account has been created") email_body = render_to_string( "account_management/admin/emails/notify_user_on_creation.txt", { "finish_registration_url": password_reset_url, "user": student_user, "PASSWORD_RESET_TIMEOUT_DAYS": settings.PASSWORD_RESET_TIMEOUT_DAYS, }, ) try: user_notification_sent = send_mail( email_subject, email_body, "*****@*****.**", [student_user.email], ) except SMTPException: logger.info(f"Failed to send email to new user {student_user}") messages.warning( self.request, f"The Student Page for {student_user} has been created. " f"A notification email failed to send to {student_user.email}. ", "Please contanct the site administrator.", ) return response else: if user_notification_sent: messages.success( self.request, f"The Student Page for {student_user} has been created. " f"A notification email has been sent to {student_user.email}", ) return response
def revisions_revert(request, page_id, revision_id): page = get_object_or_404(Page, id=page_id).specific page_perms = page.permissions_for_user(request.user) if not page_perms.can_edit(): raise PermissionDenied revision = get_object_or_404(page.revisions, id=revision_id) revision_page = revision.as_object() content_type = ContentType.objects.get_for_model(page) page_class = content_type.model_class() edit_handler = page_class.get_edit_handler() form_class = edit_handler.get_form_class() form = form_class(instance=revision_page) edit_handler = edit_handler.get_bound_panel(instance=revision_page, request=request, form=form) lock = page.get_lock() action_menu = PageActionMenu( request, view="revisions_revert", page=page, lock=lock, locked_for_user=lock is not None and lock.for_user(request.user), ) side_panels = PageSidePanels( request, page, preview_enabled=True, comments_enabled=form.show_comments_toggle, ) user_avatar = render_to_string("wagtailadmin/shared/user_avatar.html", {"user": revision.user}) messages.warning( request, mark_safe( _("You are viewing a previous version of this page from <b>%(created_at)s</b> by %(user)s" ) % { "created_at": revision.created_at.strftime("%d %b %Y %H:%M"), "user": user_avatar, }), ) return TemplateResponse( request, "wagtailadmin/pages/edit.html", { "page": page, "revision": revision, "is_revision": True, "content_type": content_type, "edit_handler": edit_handler, "errors_debug": None, "action_menu": action_menu, "side_panels": side_panels, "form": form, # Used in unit tests "media": edit_handler.media + form.media + action_menu.media + side_panels.media, }, )
def publish(request, page_id): page = get_object_or_404(Page, id=page_id).specific user_perms = UserPagePermissionsProxy(request.user) if not user_perms.for_page(page).can_publish(): raise PermissionDenied next_url = pages.get_valid_next_url_from_request(request) if request.method == 'POST': page.get_latest_revision().publish() # TODO: clean up copypasta when coa-publisher phases out previously AWS publish pipeline # Show success message if there is a publish_janis_branch set (for netlify builds) # Or default to show success message on Staging and Production (follow existing AWS implementation pattern) try: publish_janis_branch = getattr(JanisBranchSettings.objects.first(), 'publish_janis_branch') except: publish_janis_branch = None if settings.ISSTAGING or settings.ISPRODUCTION: messages.success(request, _("Page '{0}' published.").format( page.get_admin_display_title()), buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(page.id, )), _('Edit')) ]) elif settings.ISLOCAL: messages.warning( request, _("Page '{0}' not published. You're running on a local environment." ).format(page.get_admin_display_title()), buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(page.id, )), _('Edit')) ]) elif publish_janis_branch: messages.success(request, _("Page '{0}' published.").format( page.get_admin_display_title()), buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(page.id, )), _('Edit')) ]) else: messages.warning( request, _("Page '{0}' not published. No `publish_janis_branch` was set." ).format(page.get_admin_display_title()), buttons=[ messages.button( reverse('wagtailadmin_pages:edit', args=(page.id, )), _('Edit')) ]) if next_url: return redirect(next_url) # return redirect('wagtailadmin_explore', page.get_parent().id) return redirect('/admin/pages/search/') return render(request, 'wagtailadmin/pages/confirm_publish.html', { 'page': page, 'next': next_url, })