示例#1
0
def list(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permissions = [
        get_permission_name(action, model)
        for action in ['add', 'change', 'delete']
    ]
    if not any([request.user.has_perm(perm) for perm in permissions]):
        return permission_denied(request)

    items = model.objects.all()

    # Preserve the snippet's model-level ordering if specified, but fall back on PK if not
    # (to ensure pagination is consistent)
    if not items.ordered:
        items = items.order_by('pk')

    # Search
    is_searchable = class_is_indexed(model)
    is_searching = False
    search_query = None
    if is_searchable and 'q' in request.GET:
        search_form = SearchForm(request.GET, placeholder=_("Search %(snippet_type_name)s") % {
            'snippet_type_name': model._meta.verbose_name_plural
        })

        if search_form.is_valid():
            search_query = search_form.cleaned_data['q']

            search_backend = get_search_backend()
            items = search_backend.search(search_query, items)
            is_searching = True

    else:
        search_form = SearchForm(placeholder=_("Search %(snippet_type_name)s") % {
            'snippet_type_name': model._meta.verbose_name_plural
        })

    paginator = Paginator(items, per_page=20)
    paginated_items = paginator.get_page(request.GET.get('p'))

    # Template
    if request.is_ajax():
        template = 'wagtailsnippets/snippets/results.html'
    else:
        template = 'wagtailsnippets/snippets/type_index.html'

    return render(request, template, {
        'model_opts': model._meta,
        'items': paginated_items,
        'can_add_snippet': request.user.has_perm(get_permission_name('add', model)),
        'can_delete_snippets': request.user.has_perm(get_permission_name('delete', model)),
        'is_searchable': is_searchable,
        'search_form': search_form,
        'is_searching': is_searching,
        'query_string': search_query,
    })
示例#2
0
def delete(request, app_label, model_name, pk,
           template='wagtailsnippets/snippets/confirm_delete.html',
           redirect_to=_redirect_to):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('delete', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = get_object_or_404(model, pk=unquote(pk))

    if request.method == 'POST':
        instance.delete()
        messages.success(
            request,
            _("{snippet_type} '{instance}' deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                instance=instance
            )
        )
        return redirect_to(app_label, model_name)

    return render(request, template, {
        'model_opts': model._meta,
        'instance': instance,
    })
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,
        })
示例#4
0
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,
    })
示例#5
0
def create(request,
           app_label,
           model_name,
           template='wagtailsnippets/snippets/create.html',
           redirect_to=_redirect_to):
    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_to(app_label, model_name)
        else:
            messages.error(
                request, _("The snippet could not be created due to errors."))
            edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                         form=form)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                     form=form)

    return render(request, template, {
        'model_opts': model._meta,
        'edit_handler': edit_handler,
        'form': form,
    })
示例#6
0
def create(request, app_label, model_name,
           template='wagtailsnippets/snippets/create.html',
           redirect_to=_redirect_to):
    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_to(app_label, model_name)
        else:
            messages.error(request, _("The snippet could not be created due to errors."))
            edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                         form=form)
    else:
        form = form_class(instance=instance)
        edit_handler = edit_handler.bind_to_instance(instance=instance,
                                                     form=form)

    return render(request, template, {
        'model_opts': model._meta,
        'edit_handler': edit_handler,
        'form': form,
    })
def delete(request, app_label, model_name, pk=None):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('delete', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    if pk:
        instances = [get_object_or_404(model, pk=unquote(pk))]
    else:
        ids = request.GET.getlist('id')
        instances = model.objects.filter(pk__in=ids)

    count = len(instances)

    if request.method == 'POST':
        for instance in instances:
            instance.delete()

        if count == 1:
            message_content = _("{snippet_type} '{instance}' deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                instance=instance)
        else:
            message_content = _("{count} {snippet_type} deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                count=count)

        messages.success(request, message_content)

        return redirect('wagtailsnippets:list', app_label, model_name)

    return render(
        request, 'wagtailsnippets/snippets/confirm_delete.html', {
            'model_opts':
            model._meta,
            'count':
            count,
            'instances':
            instances,
            'submit_url':
            (reverse('wagtailsnippets:delete-multiple',
                     args=(app_label, model_name)) + '?' +
             urlencode([('id', instance.pk) for instance in instances])),
        })
示例#8
0
def register_snippet_listing_buttons(snippet, user, next_url=None):
    model = type(snippet)

    if user_can_edit_snippet_type(user, model):
        yield SnippetListingButton(
            _('Edit'),
            reverse('wagtailsnippets:edit', args=[model._meta.app_label, model._meta.model_name, quote(snippet.pk)]),
            attrs={'aria-label': _("Edit '%(title)s'") % {'title': str(snippet)}},
            priority=10
        )

    if user.has_perm(get_permission_name('delete', model)):
        yield SnippetListingButton(
            _('Delete'),
            reverse('wagtailsnippets:delete', args=[model._meta.app_label, model._meta.model_name, quote(snippet.pk)]),
            attrs={'aria-label': _("Delete '%(title)s'") % {'title': str(snippet)}},
            priority=20
        )
示例#9
0
def delete(request, app_label, model_name, pk=None):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('delete', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    if pk:
        instances = [get_object_or_404(model, pk=unquote(pk))]
    else:
        ids = request.GET.getlist('id')
        instances = model.objects.filter(pk__in=ids)

    count = len(instances)

    if request.method == 'POST':
        for instance in instances:
            instance.delete()

        if count == 1:
            message_content = _("{snippet_type} '{instance}' deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                instance=instance
            )
        else:
            message_content = _("{count} {snippet_type} deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                count=count
            )

        messages.success(request, message_content)

        return redirect('wagtailsnippets:list', app_label, model_name)

    return render(request, 'wagtailsnippets/snippets/confirm_delete.html', {
        'model_opts': model._meta,
        'count': count,
        'instances': instances,
        'submit_url': (
            reverse('wagtailsnippets:delete-multiple', args=(app_label, model_name))
            + '?' + urlencode([('id', instance.pk) for instance in instances])
        ),
    })
示例#10
0
def delete(request, app_label, model_name, pk):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('delete', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = get_object_or_404(model, pk=unquote(pk))

    if request.method == 'POST':
        instance.delete()
        messages.success(
            request,
            _("{snippet_type} '{instance}' deleted.").format(
                snippet_type=capfirst(model._meta.verbose_name_plural),
                instance=instance))
        return redirect('wagtailsnippets:list', app_label, model_name)

    return render(request, 'wagtailsnippets/snippets/confirm_delete.html', {
        'model_opts': model._meta,
        'instance': instance,
    })
示例#11
0
def list(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permissions = [
        get_permission_name(action, model)
        for action in ['add', 'change', 'delete']
    ]
    if not any([request.user.has_perm(perm) for perm in permissions]):
        return permission_denied(request)

    items = model.objects.all()

    # Preserve the snippet's model-level ordering if specified, but fall back on PK if not
    # (to ensure pagination is consistent)
    if not items.ordered:
        items = items.order_by('pk')

    # Search
    is_searchable = class_is_indexed(model)
    is_searching = False
    search_query = None
    if is_searchable and 'q' in request.GET:
        search_form = SearchForm(
            request.GET,
            placeholder=_("Search %(snippet_type_name)s") %
            {'snippet_type_name': model._meta.verbose_name_plural})

        if search_form.is_valid():
            search_query = search_form.cleaned_data['q']

            search_backend = get_search_backend()
            items = search_backend.search(search_query, items)
            is_searching = True

    else:
        search_form = SearchForm(
            placeholder=_("Search %(snippet_type_name)s") %
            {'snippet_type_name': model._meta.verbose_name_plural})

    paginator = Paginator(items, per_page=20)
    paginated_items = paginator.get_page(request.GET.get('p'))

    # Template
    if request.is_ajax():
        template = 'wagtailsnippets/snippets/results.html'
    else:
        template = 'wagtailsnippets/snippets/type_index.html'

    return TemplateResponse(
        request, template, {
            'model_opts':
            model._meta,
            'items':
            paginated_items,
            'can_add_snippet':
            request.user.has_perm(get_permission_name('add', model)),
            'can_delete_snippets':
            request.user.has_perm(get_permission_name('delete', model)),
            'is_searchable':
            is_searchable,
            'search_form':
            search_form,
            'is_searching':
            is_searching,
            'query_string':
            search_query,
        })
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,
            ),
        },
    )
示例#13
0
def edit(request, poll_pk):
    from ..models import Poll
    model = Poll
    poll = get_object_or_404(Poll, pk=poll_pk)

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    instance = poll

    for fn in hooks.get_hooks('before_edit_snippet'):
        result = fn(request, instance)
        if hasattr(result, 'status_code'):
            return result

    edit_handler = get_poll_edit_handler(Poll)
    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('wagtailpolls_edit', args=(poll, )), _('Edit'))
                ])

            for fn in hooks.get_hooks('after_edit_snippet'):
                result = fn(request, instance)
                if hasattr(result, 'status_code'):
                    return result

            return redirect('wagtailpolls_index')
        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, 'wagtailpolls/edit.html', {
            'modal_opts': model._meta,
            'instance': instance,
            'poll': instance,
            'edit_handler': edit_handler,
            'form': form
        })
示例#14
0
 def is_shown(self, context):
     if context["view"] == "edit" and context["instance"].live:
         publish_permission = get_permission_name("publish",
                                                  context["model"])
         return context["request"].user.has_perm(publish_permission)
     return False
示例#15
0
 def is_shown(self, context):
     publish_permission = get_permission_name("publish", context["model"])
     return context["request"].user.has_perm(publish_permission)
示例#16
0
    def is_shown(self, context):
        delete_permission = get_permission_name("delete", context["model"])

        return context["view"] == "edit" and context["request"].user.has_perm(
            delete_permission)
示例#17
0
def copy(request, app_label, model_name, id):
    # Validate snippet has been registered and title_field is set.
    meta = snippet_copy_registry.get(app_label, model_name)
    if meta is None:
        raise Exception("This snippet isn't registered as copyable")

    try:
        model = apps.get_model(app_label, model_name)
    except LookupError:
        raise Http404

    permission = get_permission_name('change', model)
    if not request.user.has_perm(permission):
        return permission_denied(request)

    snippet = get_object_or_404(model, id=id)

    # Create the form
    form = meta['copy_form_class'](request.POST or None,
                                   snippet=snippet,
                                   title_field_name=meta['title_field_name'])

    next_url = get_valid_next_url_from_request(request)

    for fn in hooks.get_hooks('before_copy_snippet'):
        result = fn(request, snippet)
        if hasattr(result, 'status_code'):
            return result

    # Check if user is submitting
    if request.method == 'POST':

        if form.is_valid():

            # Copy the snippet
            new_snippet = form.copy()

            # Give a success message back to the user
            messages.success(
                request,
                _(f"{snippet.get_snippet_verbose_name()} '{snippet}' has been copied."
                  ).format(snippet))

            for fn in hooks.get_hooks('after_copy_snippet'):
                result = fn(request, snippet, new_snippet)
                if hasattr(result, 'status_code'):
                    return result

            if next_url:
                return redirect(next_url)

            if 'wagtail.contrib.modeladmin' in settings.INSTALLED_APPS:
                url_helper = AdminURLHelper(new_snippet)
                return redirect(
                    url_helper.get_action_url('edit', quote(new_snippet.pk)))

            return redirect('wagtailsnippets:edit', app_label, model_name,
                            new_snippet.id)

    return render(
        request, 'wagtailsnippetscopy/copy.html', {
            'snippet': snippet,
            'app_label': app_label,
            'model_name': model_name,
            'form': form,
            'next': next_url,
        })
示例#18
0
文件: snippets.py 项目: jams2/wagtail
def delete(request, app_label, model_name, pk=None):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name("delete", model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    if pk:
        instances = [get_object_or_404(model, pk=unquote(pk))]
    else:
        ids = request.GET.getlist("id")
        instances = model.objects.filter(pk__in=ids)

    for fn in hooks.get_hooks("before_delete_snippet"):
        result = fn(request, instances)
        if hasattr(result, "status_code"):
            return result

    count = len(instances)

    if request.method == "POST":
        with transaction.atomic():
            for instance in instances:
                log(instance=instance, action="wagtail.delete")
                instance.delete()

        if count == 1:
            message_content = _("%(snippet_type)s '%(instance)s' deleted.") % {
                "snippet_type": capfirst(model._meta.verbose_name),
                "instance": instance,
            }
        else:
            # This message is only used in plural form, but we'll define it with ngettext so that
            # languages with multiple plural forms can be handled correctly (or, at least, as
            # correctly as possible within the limitations of verbose_name_plural...)
            message_content = ngettext(
                "%(count)d %(snippet_type)s deleted.",
                "%(count)d %(snippet_type)s deleted.",
                count,
            ) % {
                "snippet_type": capfirst(model._meta.verbose_name_plural),
                "count": count,
            }

        messages.success(request, message_content)

        for fn in hooks.get_hooks("after_delete_snippet"):
            result = fn(request, instances)
            if hasattr(result, "status_code"):
                return result

        return redirect("wagtailsnippets:list", app_label, model_name)

    return TemplateResponse(
        request,
        "wagtailsnippets/snippets/confirm_delete.html",
        {
            "model_opts":
            model._meta,
            "count":
            count,
            "instances":
            instances,
            "submit_url":
            (reverse("wagtailsnippets:delete-multiple",
                     args=(app_label, model_name)) + "?" +
             urlencode([("id", instance.pk) for instance in instances])),
        },
    )
示例#19
0
def list(request, app_label, model_name):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permissions = [
        get_permission_name(action, model)
        for action in ['add', 'change', 'delete']
    ]
    if not any([request.user.has_perm(perm) for perm in permissions]):
        raise PermissionDenied

    items = model.objects.all()
    enable_locale_filter = getattr(settings, 'WAGTAIL_I18N_ENABLED',
                                   False) and issubclass(
                                       model, TranslatableMixin)

    if enable_locale_filter:
        if 'locale' in request.GET:
            try:
                locale = Locale.objects.get(
                    language_code=request.GET['locale'])
            except Locale.DoesNotExist:
                # Redirect to snippet without locale
                return redirect('wagtailsnippets:list', app_label, model_name)
        else:
            # Default to active locale (this will take into account the user's chosen admin language)
            locale = Locale.get_active()

        items = items.filter(locale=locale)

    else:
        locale = None

    # Preserve the snippet's model-level ordering if specified, but fall back on PK if not
    # (to ensure pagination is consistent)
    if not items.ordered:
        items = items.order_by('pk')

    # Search
    is_searchable = class_is_indexed(model)
    is_searching = False
    search_query = None
    if is_searchable and 'q' in request.GET:
        search_form = SearchForm(
            request.GET,
            placeholder=_("Search %(snippet_type_name)s") %
            {'snippet_type_name': model._meta.verbose_name_plural})

        if search_form.is_valid():
            search_query = search_form.cleaned_data['q']

            search_backend = get_search_backend()
            items = search_backend.search(search_query, items)
            is_searching = True

    else:
        search_form = SearchForm(
            placeholder=_("Search %(snippet_type_name)s") %
            {'snippet_type_name': model._meta.verbose_name_plural})

    paginator = Paginator(items, per_page=20)
    paginated_items = paginator.get_page(request.GET.get('p'))

    # Template
    if request.is_ajax():
        template = 'wagtailsnippets/snippets/results.html'
    else:
        template = 'wagtailsnippets/snippets/type_index.html'

    context = {
        'model_opts':
        model._meta,
        'items':
        paginated_items,
        'can_add_snippet':
        request.user.has_perm(get_permission_name('add', model)),
        'can_delete_snippets':
        request.user.has_perm(get_permission_name('delete', model)),
        'is_searchable':
        is_searchable,
        'search_form':
        search_form,
        'is_searching':
        is_searching,
        'query_string':
        search_query,
        'locale':
        None,
        'translations': [],
    }

    if enable_locale_filter:
        context.update({
            'locale':
            locale,
            'translations': [{
                'locale':
                locale,
                'url':
                reverse('wagtailsnippets:list', args=[app_label, model_name]) +
                '?locale=' + locale.language_code
            } for locale in Locale.objects.all().exclude(id=locale.id)],
        })

    return TemplateResponse(request, template, context)
示例#20
0
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)
示例#21
0
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        items = self.model.objects.all()
        enable_locale_filter = getattr(settings, 'WAGTAIL_I18N_ENABLED',
                                       False) and issubclass(
                                           self.model, TranslatableMixin)

        if enable_locale_filter:
            if 'locale' in self.request.GET:
                try:
                    locale = Locale.objects.get(
                        language_code=self.request.GET['locale'])
                except Locale.DoesNotExist:
                    # Redirect to snippet without locale
                    return redirect('wagtailsnippets:list', self.app_label,
                                    self.model_name)
            else:
                # Default to active locale (this will take into account the user's chosen admin language)
                locale = Locale.get_active()

            items = items.filter(locale=locale)

        else:
            locale = None

        # Preserve the snippet's model-level ordering if specified, but fall back on PK if not
        # (to ensure pagination is consistent)
        if not items.ordered:
            items = items.order_by('pk')

        # Search
        is_searchable = class_is_indexed(self.model)
        is_searching = False
        search_query = None
        if is_searchable and 'q' in self.request.GET:
            search_form = SearchForm(
                self.request.GET,
                placeholder=_("Search %(snippet_type_name)s") %
                {'snippet_type_name': self.model._meta.verbose_name_plural})

            if search_form.is_valid():
                search_query = search_form.cleaned_data['q']

                search_backend = get_search_backend()
                items = search_backend.search(search_query, items)
                is_searching = True

        else:
            search_form = SearchForm(
                placeholder=_("Search %(snippet_type_name)s") %
                {'snippet_type_name': self.model._meta.verbose_name_plural})

        paginator = Paginator(items, per_page=20)
        paginated_items = paginator.get_page(self.request.GET.get('p'))

        context.update({
            'model_opts':
            self.model._meta,
            'items':
            paginated_items,
            'can_add_snippet':
            self.request.user.has_perm(get_permission_name('add', self.model)),
            'can_delete_snippets':
            self.request.user.has_perm(
                get_permission_name('delete', self.model)),
            'is_searchable':
            is_searchable,
            'search_form':
            search_form,
            'is_searching':
            is_searching,
            'query_string':
            search_query,
            'locale':
            None,
            'translations': [],
        })

        if enable_locale_filter:
            context.update({
                'locale':
                locale,
                'translations': [{
                    'locale':
                    locale,
                    'url':
                    reverse('wagtailsnippets:list',
                            args=[self.app_label, self.model_name]) +
                    '?locale=' + locale.language_code
                } for locale in Locale.objects.all().exclude(id=locale.id)],
            })

        return context
示例#22
0
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,
            'action_menu':
            SnippetActionMenu(request, view='edit', instance=instance),
        })
示例#23
0
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)
        })
示例#24
0
    def is_shown(self, context):
        delete_permission = get_permission_name('delete', context['model'])

        return (context['view'] == 'edit'
                and context['request'].user.has_perm(delete_permission))
示例#25
0
文件: snippets.py 项目: jams2/wagtail
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        items = self.model.objects.all()
        enable_locale_filter = getattr(settings, "WAGTAIL_I18N_ENABLED",
                                       False) and issubclass(
                                           self.model, TranslatableMixin)

        if enable_locale_filter:
            if "locale" in self.request.GET:
                try:
                    locale = Locale.objects.get(
                        language_code=self.request.GET["locale"])
                except Locale.DoesNotExist:
                    # Redirect to snippet without locale
                    return redirect("wagtailsnippets:list", self.app_label,
                                    self.model_name)
            else:
                # Default to active locale (this will take into account the user's chosen admin language)
                locale = Locale.get_active()

            items = items.filter(locale=locale)

        else:
            locale = None

        # Preserve the snippet's model-level ordering if specified, but fall back on PK if not
        # (to ensure pagination is consistent)
        if not items.ordered:
            items = items.order_by("pk")

        # Search
        is_searchable = class_is_indexed(self.model)
        is_searching = False
        search_query = None
        if is_searchable and "q" in self.request.GET:
            search_form = SearchForm(
                self.request.GET,
                placeholder=_("Search %(snippet_type_name)s") %
                {"snippet_type_name": self.model._meta.verbose_name_plural},
            )

            if search_form.is_valid():
                search_query = search_form.cleaned_data["q"]

                search_backend = get_search_backend()
                items = search_backend.search(search_query, items)
                is_searching = True

        else:
            search_form = SearchForm(
                placeholder=_("Search %(snippet_type_name)s") %
                {"snippet_type_name": self.model._meta.verbose_name_plural})

        paginator = Paginator(items, per_page=20)
        paginated_items = paginator.get_page(self.request.GET.get("p"))

        context.update({
            "model_opts":
            self.model._meta,
            "items":
            paginated_items,
            "can_add_snippet":
            self.request.user.has_perm(get_permission_name("add", self.model)),
            "can_delete_snippets":
            self.request.user.has_perm(
                get_permission_name("delete", self.model)),
            "is_searchable":
            is_searchable,
            "search_form":
            search_form,
            "is_searching":
            is_searching,
            "query_string":
            search_query,
            "locale":
            None,
            "translations": [],
        })

        if enable_locale_filter:
            context.update({
                "locale":
                locale,
                "translations": [{
                    "locale":
                    locale,
                    "url":
                    reverse(
                        "wagtailsnippets:list",
                        args=[self.app_label, self.model_name],
                    ) + "?locale=" + locale.language_code,
                } for locale in Locale.objects.all().exclude(id=locale.id)],
            })

        return context
示例#26
0
文件: snippets.py 项目: jams2/wagtail
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)
示例#27
0
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)
示例#28
0
文件: snippets.py 项目: jams2/wagtail
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)
示例#29
0
def delete(request, app_label, model_name, pk=None):
    model = get_snippet_model_from_url_params(app_label, model_name)

    permission = get_permission_name('delete', model)
    if not request.user.has_perm(permission):
        raise PermissionDenied

    if pk:
        instances = [get_object_or_404(model, pk=unquote(pk))]
    else:
        ids = request.GET.getlist('id')
        instances = model.objects.filter(pk__in=ids)

    for fn in hooks.get_hooks('before_delete_snippet'):
        result = fn(request, instances)
        if hasattr(result, 'status_code'):
            return result

    count = len(instances)

    if request.method == 'POST':
        for instance in instances:
            instance.delete()

        if count == 1:
            message_content = _("%(snippet_type)s '%(instance)s' deleted.") % {
                'snippet_type': capfirst(model._meta.verbose_name),
                'instance': instance
            }
        else:
            # This message is only used in plural form, but we'll define it with ngettext so that
            # languages with multiple plural forms can be handled correctly (or, at least, as
            # correctly as possible within the limitations of verbose_name_plural...)
            message_content = ngettext(
                "%(count)d %(snippet_type)s deleted.",
                "%(count)d %(snippet_type)s deleted.", count) % {
                    'snippet_type': capfirst(model._meta.verbose_name_plural),
                    'count': count
                }

        messages.success(request, message_content)

        for fn in hooks.get_hooks('after_delete_snippet'):
            result = fn(request, instances)
            if hasattr(result, 'status_code'):
                return result

        return redirect('wagtailsnippets:list', app_label, model_name)

    return TemplateResponse(
        request, 'wagtailsnippets/snippets/confirm_delete.html', {
            'model_opts':
            model._meta,
            'count':
            count,
            'instances':
            instances,
            'submit_url':
            (reverse('wagtailsnippets:delete-multiple',
                     args=(app_label, model_name)) + '?' +
             urlencode([('id', instance.pk) for instance in instances])),
        })
示例#30
0
文件: delete.py 项目: tnir/wagtail
 def check_perm(self, snippet):
     if getattr(self, "can_delete_items", None) is None:
         # since snippets permissions are not enforced per object, makes sense to just check once per model request
         self.can_delete_items = self.request.user.has_perm(
             get_permission_name("delete", self.model))
     return self.can_delete_items