コード例 #1
0
ファイル: git.py プロジェクト: nijel/weblate
def update_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('vcs.update', obj):
        raise PermissionDenied()

    return perform_update(request, obj)
コード例 #2
0
ファイル: git.py プロジェクト: nijel/weblate
def push_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('vcs.push', obj):
        raise PermissionDenied()

    return perform_push(request, obj)
コード例 #3
0
ファイル: manage.py プロジェクト: dekoza/weblate
def move_component(request, project, component):
    obj = get_component(request, project, component)
    return perform_rename(
        ComponentMoveForm, request, obj, 'project.edit',
        component=obj, target=obj.project.slug,
        action=Change.ACTION_MOVE_COMPONENT
    )
コード例 #4
0
ファイル: manage.py プロジェクト: nijel/weblate
def component_progress_terminate(request, project, component):
    obj = get_component(request, project, component)

    if obj.in_progress and request.user.has_perm('component.edit', obj):
        obj.background_task.revoke(terminate=True)

    return redirect(obj)
コード例 #5
0
ファイル: agreement.py プロジェクト: dekoza/weblate
def agreement_confirm(request, project, component):
    component = get_component(request, project, component)

    has_agreed = ContributorAgreement.objects.has_agreed(
        request.user, component
    )

    if request.method == 'POST':
        form = ContributorAgreementForm(request.POST)
        if form.is_valid() and not has_agreed:
            ContributorAgreement.objects.create(
                user=request.user,
                component=component
            )
            return redirect_next(
                request.GET.get('next'),
                component.get_absolute_url(),
            )
    else:
        form = ContributorAgreementForm(
            initial={
                'next': request.GET.get('next'),
                'confirm': has_agreed,
            }
        )

    return render(
        request,
        'contributor-agreement.html',
        {
            'form': form,
            'object': component,
            'has_agreed': has_agreed,
        }
    )
コード例 #6
0
ファイル: settings.py プロジェクト: dekoza/weblate
def change_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.edit', obj):
        raise Http404()

    if request.method == 'POST':
        form = ComponentSettingsForm(request, request.POST, instance=obj)
        if form.is_valid():
            form.save()
            messages.success(request, _('Settings saved'))
            return redirect(
                'settings', project=obj.project.slug, component=obj.slug
            )
        else:
            messages.error(
                request,
                _('Invalid settings, please check the form for errors!')
            )
    else:
        form = ComponentSettingsForm(request, instance=obj)

    return render(
        request,
        'component-settings.html',
        {
            'project': obj.project,
            'object': obj,
            'form': form,
        }
    )
コード例 #7
0
ファイル: git.py プロジェクト: nijel/weblate
def cleanup_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('vcs.reset', obj):
        raise PermissionDenied()

    return perform_cleanup(request, obj)
コード例 #8
0
ファイル: source.py プロジェクト: nijel/weblate
def matrix(request, project, component):
    """Matrix view of all strings"""
    obj = get_component(request, project, component)

    show = False
    languages = None
    language_codes = None

    if 'lang' in request.GET:
        form = MatrixLanguageForm(obj, request.GET)
        show = form.is_valid()
    else:
        form = MatrixLanguageForm(obj)

    if show:
        languages = Language.objects.filter(
            code__in=form.cleaned_data['lang']
        )
        language_codes = ','.join(languages.values_list('code', flat=True))

    return render(
        request,
        'matrix.html',
        {
            'object': obj,
            'project': obj.project,
            'languages': languages,
            'language_codes': language_codes,
            'languages_form': form,
        }
    )
コード例 #9
0
ファイル: views.py プロジェクト: nijel/weblate
def mute_component(request, project, component):
    obj = get_component(request, project, component)
    mute_real(request.user, scope=SCOPE_COMPONENT, component=obj, project=None)
    return redirect(
        '{}?notify_component={}#notifications'.format(
            reverse('profile'), obj.pk
        )
    )
コード例 #10
0
ファイル: manage.py プロジェクト: nijel/weblate
def component_progress_js(request, project, component):
    obj = get_component(request, project, component)
    progress, log = obj.get_progress()
    return JsonResponse({
        'in_progress': obj.in_progress(),
        'progress': progress,
        'log': '\n'.join(log)
    })
コード例 #11
0
ファイル: source.py プロジェクト: nijel/weblate
def get_source(request, project, component):
    """
    Returns first translation in component
    (this assumes all have same source strings).
    """
    obj = get_component(request, project, component)
    try:
        return obj, obj.translation_set.all()[0]
    except (Translation.DoesNotExist, IndexError):
        raise Http404('No translation exists in this component.')
コード例 #12
0
ファイル: basic.py プロジェクト: nijel/weblate
def new_language(request, project, component):
    obj = get_component(request, project, component)

    form_class = get_new_language_form(request, obj)
    can_add = obj.can_add_new_language(request)

    if request.method == 'POST':
        form = form_class(obj, request.POST)

        if form.is_valid():
            langs = form.cleaned_data['lang']
            kwargs = {
                'user': request.user,
                'author': request.user,
                'component': obj,
                'details': {},
            }
            for language in Language.objects.filter(code__in=langs):
                kwargs['details']['language'] = language.code
                if can_add:
                    obj.add_new_language(language, request)
                    Change.objects.create(
                        action=Change.ACTION_ADDED_LANGUAGE,
                        **kwargs
                    )
                elif obj.new_lang == 'contact':
                    Change.objects.create(
                        action=Change.ACTION_REQUESTED_LANGUAGE,
                        **kwargs
                    )
                    messages.success(
                        request,
                        _(
                            "A request for a new translation has been "
                            "sent to the project's maintainers."
                        )
                    )
            return redirect(obj)
        messages.error(
            request,
            _('Please fix errors in the form.')
        )
    else:
        form = form_class(obj)

    return render(
        request,
        'new-language.html',
        {
            'object': obj,
            'project': obj.project,
            'form': form,
            'can_add': can_add,
        }
    )
コード例 #13
0
ファイル: lock.py プロジェクト: dekoza/weblate
def unlock_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.lock', obj):
        raise PermissionDenied()

    obj.do_lock(request.user, False)

    messages.success(
        request,
        _('Component is now open for translation updates.')
    )

    return redirect_param(obj, '#repository')
コード例 #14
0
def new_language(request, project, component):
    obj = get_component(request, project, component)

    form_class = get_new_language_form(request, obj)
    can_add = obj.can_add_new_language(request)

    if request.method == 'POST':
        form = form_class(obj, request.POST)

        if form.is_valid():
            langs = form.cleaned_data['lang']
            kwargs = {
                'user': request.user,
                'author': request.user,
                'component': obj,
                'details': {},
            }
            for language in Language.objects.filter(code__in=langs):
                kwargs['details']['language'] = language.code
                if can_add:
                    translation = obj.add_new_language(language, request)
                    if translation:
                        kwargs['translation'] = translation
                        if len(langs) == 1:
                            obj = translation
                        Change.objects.create(
                            action=Change.ACTION_ADDED_LANGUAGE, **kwargs
                        )
                elif obj.new_lang == 'contact':
                    Change.objects.create(
                        action=Change.ACTION_REQUESTED_LANGUAGE, **kwargs
                    )
                    messages.success(
                        request,
                        _(
                            "A request for a new translation has been "
                            "sent to the project's maintainers."
                        ),
                    )
            return redirect(obj)
        messages.error(request, _('Please fix errors in the form.'))
    else:
        form = form_class(obj)

    return render(
        request,
        'new-language.html',
        {'object': obj, 'project': obj.project, 'form': form, 'can_add': can_add},
    )
コード例 #15
0
ファイル: widgets.py プロジェクト: dekoza/weblate
def render_widget(request, project, widget='287x66', color=None, lang=None,
                  component=None, extension='png'):
    # We intentionally skip ACL here to allow widget sharing
    if component is None:
        obj = get_project(request, project, skip_acl=True)
    else:
        obj = get_component(request, project, component, skip_acl=True)

    # Handle language parameter
    if lang is not None:
        if 'native' not in request.GET:
            try_set_language(lang)
        lang = Language.objects.try_get(code=lang)
    else:
        try_set_language('en')

    # Get widget class
    try:
        widget_class = WIDGETS[widget]
    except KeyError:
        raise Http404()

    # Construct object
    widget_obj = widget_class(obj, color, lang)

    # Redirect widget
    if hasattr(widget_obj, 'redirect'):
        return redirect(widget_obj.redirect(), permanent=True)

    # Invalid extension
    if extension != widget_obj.extension or color != widget_obj.color:
        kwargs = {
            'project': project,
            'widget': widget,
            'color': widget_obj.color,
            'extension': widget_obj.extension,
        }
        if lang:
            kwargs['lang'] = lang.code
            return redirect('widget-image', permanent=True, **kwargs)
        return redirect('widget-image', permanent=True, **kwargs)

    # Render widget
    widget_obj.render()

    return HttpResponse(
        content_type=widget_obj.content_type,
        content=widget_obj.get_content()
    )
コード例 #16
0
def new_language(request, project, component):
    obj = get_component(request, project, component)

    form_class = get_new_language_form(request, obj)
    can_add = obj.can_add_new_language(request.user)

    if request.method == "POST":
        form = form_class(obj, request.POST)

        if form.is_valid():
            langs = form.cleaned_data["lang"]
            kwargs = {
                "user": request.user,
                "author": request.user,
                "component": obj,
                "details": {},
            }
            for language in Language.objects.filter(code__in=langs):
                kwargs["details"]["language"] = language.code
                if can_add:
                    translation = obj.add_new_language(language, request)
                    if translation:
                        kwargs["translation"] = translation
                        if len(langs) == 1:
                            obj = translation
                        Change.objects.create(
                            action=Change.ACTION_ADDED_LANGUAGE, **kwargs
                        )
                elif obj.new_lang == "contact":
                    Change.objects.create(
                        action=Change.ACTION_REQUESTED_LANGUAGE, **kwargs
                    )
                    messages.success(
                        request,
                        _(
                            "A request for a new translation has been "
                            "sent to the project's maintainers."
                        ),
                    )
            return redirect(obj)
        messages.error(request, _("Please fix errors in the form."))
    else:
        form = form_class(obj)

    return render(
        request,
        "new-language.html",
        {"object": obj, "project": obj.project, "form": form, "can_add": can_add},
    )
コード例 #17
0
def dismiss_alert(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("component.edit", obj):
        raise Http404()

    try:
        alert = obj.alert_set.get(name=request.POST["dismiss"])
        if alert.obj.dismissable:
            alert.dismissed = True
            alert.save(update_fields=["dismissed"])
    except ObjectDoesNotExist:
        pass

    return redirect_param(obj, "#alerts")
コード例 #18
0
ファイル: manage.py プロジェクト: bofalke/weblate
def component_progress(request, project, component):
    obj = get_component(request, project, component)
    return_url = 'component' if 'info' in request.get else 'guide'
    if not obj.in_progress():
        return redirect(return_url, **obj.get_reverse_url_kwargs())

    progress, log = obj.get_progress()

    return render(
        request, 'component-progress.html', {
            'object': obj,
            'progress': progress,
            'log': '\n'.join(log),
            'return_url': return_url,
        })
コード例 #19
0
ファイル: settings.py プロジェクト: lcsouzamenezes/weblate
def remove_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("component.edit", obj):
        raise PermissionDenied()

    form = ComponentDeleteForm(obj, request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, "#delete")

    component_removal.delay(obj.pk, request.user.pk)
    messages.success(request, _("Translation component was scheduled for removal."))

    return redirect(obj.project)
コード例 #20
0
ファイル: widgets.py プロジェクト: wellart/weblate
def render_widget(request, project, widget='287x66', color=None, lang=None,
                  component=None, extension='png'):
    # We intentionally skip ACL here to allow widget sharing
    if component is None:
        obj = get_project(request, project, skip_acl=True)
    else:
        obj = get_component(request, project, component, skip_acl=True)

    # Handle language parameter
    if lang is not None:
        lang = Language.objects.fuzzy_get(code=lang, strict=True)
        if lang is None:
            raise Http404()
        if 'native' not in request.GET:
            try_set_language(lang.code)
    else:
        try_set_language('en')

    # Get widget class
    try:
        widget_class = WIDGETS[widget]
    except KeyError:
        raise Http404()

    # Construct object
    widget_obj = widget_class(obj, color, lang)

    # Redirect widget
    if hasattr(widget_obj, 'redirect'):
        return redirect(widget_obj.redirect(), permanent=True)

    # Invalid extension
    if extension != widget_obj.extension or color != widget_obj.color:
        kwargs = {
            'project': project,
            'widget': widget,
            'color': widget_obj.color,
            'extension': widget_obj.extension,
        }
        if lang:
            kwargs['lang'] = lang.code
            return redirect('widget-image', permanent=True, **kwargs)
        return redirect('widget-image', permanent=True, **kwargs)

    # Render widget
    response = HttpResponse(content_type=widget_obj.content_type)
    widget_obj.render(response)
    return response
コード例 #21
0
ファイル: views.py プロジェクト: renatofb/weblate
def git_export(request, project, component, path):
    """Git HTTP server view.

    Wrapper around git-http-backend to provide Git repositories export over HTTP.
    Performs permission checks and hands over execution to the wrapper.
    """
    # Probably browser access
    if not path:
        return redirect("component",
                        project=project,
                        component=component,
                        permanent=False)
    # Strip possible double path separators
    path = path.lstrip("/\\")

    # HTTP authentication
    auth = request.META.get("HTTP_AUTHORIZATION", b"")

    # Reject non pull access early
    if request.GET.get("service", "") not in ("", "git-upload-pack"):
        raise PermissionDenied("Only pull is supported")

    if auth and not authenticate(request, auth):
        return response_authenticate()

    # Permissions
    try:
        obj = get_component(request, project, component)
    except Http404:
        if not request.user.is_authenticated:
            return response_authenticate()
        raise
    if not request.user.has_perm("vcs.access", obj):
        if not request.user.is_authenticated:
            return response_authenticate()
        raise PermissionDenied("No VCS permissions")
    if obj.vcs not in SUPPORTED_VCS:
        raise Http404("Not a git repository")
    if obj.is_repo_link:
        kwargs = obj.linked_component.get_reverse_url_kwargs()
        kwargs["path"] = path
        return redirect(
            "{}?{}".format(reverse("git-export", kwargs=kwargs),
                           request.META["QUERY_STRING"]),
            permanent=True,
        )

    return run_git_http(request, obj, path)
コード例 #22
0
ファイル: basic.py プロジェクト: wellart/weblate
def show_component(request, project, component):
    obj = get_component(request, project, component)
    user = request.user

    last_changes = Change.objects.prefetch().order().filter(component=obj)[:10]

    return render(
        request,
        'component.html',
        {
            'allow_index': True,
            'object': obj,
            'hide_alerts': True,
            'project': obj.project,
            'translations': sort_objects(
                prefetch_stats(obj.translation_set.prefetch())
            ),
            'reports_form': ReportsForm(),
            'last_changes': last_changes,
            'last_changes_url': urlencode(
                {'component': obj.slug, 'project': obj.project.slug}
            ),
            'language_count': Language.objects.filter(
                translation__component=obj
            ).distinct().count(),
            'replace_form': optional_form(ReplaceForm, user, 'unit.edit', obj),
            'bulk_state_form': optional_form(
                BulkStateForm, user, 'translation.auto', obj,
                user=user, obj=obj
            ),
            'whiteboard_form': optional_form(
                WhiteboardForm, user, 'component.edit', obj
            ),
            'delete_form': optional_form(
                DeleteForm, user, 'component.edit', obj, obj=obj
            ),
            'rename_form': optional_form(
                ComponentRenameForm, user, 'component.edit', obj,
                request=request, instance=obj
            ),
            'move_form': optional_form(
                ComponentMoveForm, user, 'component.edit', obj,
                request=request, instance=obj
            ),
            'search_form': SearchForm(request.user),
            'alerts': obj.alert_set.order_by('name'),
        }
    )
コード例 #23
0
ファイル: manage.py プロジェクト: urbalazs/weblate
def whiteboard_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.edit', obj):
        raise PermissionDenied()

    form = WhiteboardForm(request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#whiteboard')

    WhiteboardMessage.objects.create(project=obj.project,
                                     component=obj,
                                     **form.cleaned_data)

    return redirect(obj)
コード例 #24
0
ファイル: manage.py プロジェクト: nijel/weblate
def component_progress(request, project, component):
    obj = get_component(request, project, component)
    if not obj.in_progress():
        return redirect(obj)

    progress, log = obj.get_progress()

    return render(
        request,
        'component-progress.html',
        {
            'object': obj,
            'progress': progress,
            'log': '\n'.join(log),
        }
    )
コード例 #25
0
ファイル: settings.py プロジェクト: lcsouzamenezes/weblate
def announcement_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("component.edit", obj):
        raise PermissionDenied()

    form = AnnouncementForm(request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, "#announcement")

    Announcement.objects.create(
        user=request.user, project=obj.project, component=obj, **form.cleaned_data
    )

    return redirect(obj)
コード例 #26
0
ファイル: basic.py プロジェクト: nijel/weblate
def show_component(request, project, component):
    obj = get_component(request, project, component)
    user = request.user

    last_changes = Change.objects.prefetch().filter(component=obj)[:10]

    return render(
        request,
        'component.html',
        {
            'allow_index': True,
            'object': obj,
            'project': obj.project,
            'translations': sort_objects(
                prefetch_stats(obj.translation_set.all())
            ),
            'show_language': 1,
            'reports_form': ReportsForm(),
            'last_changes': last_changes,
            'last_changes_url': urlencode(
                {'component': obj.slug, 'project': obj.project.slug}
            ),
            'language_count': Language.objects.filter(
                translation__component=obj
            ).distinct().count(),
            'replace_form': optional_form(ReplaceForm, user, 'unit.edit', obj),
            'bulk_state_form': optional_form(
                BulkStateForm, user, 'translation.auto', obj,
                user=user, obj=obj
            ),
            'whiteboard_form': optional_form(
                WhiteboardForm, user, 'component.edit', obj
            ),
            'delete_form': optional_form(
                DeleteForm, user, 'component.edit', obj, obj=obj
            ),
            'rename_form': optional_form(
                ComponentRenameForm, user, 'component.edit', obj,
                request=request, instance=obj
            ),
            'move_form': optional_form(
                ComponentMoveForm, user, 'component.edit', obj,
                request=request, instance=obj
            ),
            'search_form': SearchForm(),
        }
    )
コード例 #27
0
ファイル: basic.py プロジェクト: sunner/weblate
def show_component(request, project, component):
    obj = get_component(request, project, component)

    last_changes = Change.objects.prefetch().filter(component=obj)[:10]

    # Is user allowed to do automatic translation?
    if request.user.has_perm('translation.auto', obj):
        mass_state_form = MassStateForm(request.user, obj)
    else:
        mass_state_form = None

    if request.user.has_perm('unit.edit', obj):
        replace_form = ReplaceForm()
    else:
        replace_form = None

    return render(
        request, 'component.html', {
            'allow_index':
            True,
            'object':
            obj,
            'project':
            obj.project,
            'translations':
            sort_objects(prefetch_stats(obj.translation_set.all())),
            'show_language':
            1,
            'reports_form':
            ReportsForm(),
            'last_changes':
            last_changes,
            'last_changes_url':
            urlencode({
                'component': obj.slug,
                'project': obj.project.slug
            }),
            'language_count':
            Language.objects.filter(
                translation__component=obj).distinct().count(),
            'replace_form':
            replace_form,
            'mass_state_form':
            mass_state_form,
            'search_form':
            SearchForm(),
        })
コード例 #28
0
ファイル: views.py プロジェクト: wellart/weblate
def git_export(request, project, component, path):
    """Git HTTP server view.

    Wrapper around git-http-backend to provide Git repositories export over
    HTTP. Performs permission checks and hands over execution to the wrapper.
    """
    # Probably browser access
    if not path:
        return redirect(
            'component', project=project, component=component, permanent=False
        )
    # Strip possible double path separators
    path = path.lstrip('/\\')

    # HTTP authentication
    auth = request.META.get('HTTP_AUTHORIZATION', b'')

    # Reject non pull access early
    if request.GET.get('service', '') not in ('', 'git-upload-pack'):
        raise PermissionDenied('Only pull is supported')

    if auth and not authenticate(request, auth):
        return response_authenticate()

    # Permissions
    try:
        obj = get_component(request, project, component)
    except Http404:
        if not request.user.is_authenticated:
            return response_authenticate()
        raise
    if not request.user.has_perm('vcs.access', obj):
        raise PermissionDenied('No VCS permissions')
    if obj.vcs not in SUPPORTED_VCS:
        raise Http404('Not a git repository')
    if obj.is_repo_link:
        kwargs = obj.linked_component.get_reverse_url_kwargs()
        kwargs['path'] = path
        return redirect(
            '{}?{}'.format(
                reverse('git-export', kwargs=kwargs), request.META['QUERY_STRING']
            ),
            permanent=True,
        )

    return run_git_http(request, obj, path)
コード例 #29
0
ファイル: manage.py プロジェクト: nijel/weblate
def whiteboard_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.edit', obj):
        raise PermissionDenied()

    form = WhiteboardForm(request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#whiteboard')

    WhiteboardMessage.objects.create(
        project=obj.project,
        component=obj,
        **form.cleaned_data
    )

    return redirect(obj)
コード例 #30
0
ファイル: settings.py プロジェクト: lcsouzamenezes/weblate
def component_progress(request, project, component):
    obj = get_component(request, project, component)
    return_url = "component" if "info" in request.GET else "guide"
    if not obj.in_progress():
        return redirect(return_url, **obj.get_reverse_url_kwargs())

    progress, log = obj.get_progress()

    return render(
        request,
        "component-progress.html",
        {
            "object": obj,
            "progress": progress,
            "log": "\n".join(log),
            "return_url": return_url,
        },
    )
コード例 #31
0
def get_detail(request, project, component, checksum):
    """Return source translation detail in all languages."""
    component = get_component(request, project, component)
    try:
        units = Unit.objects.filter(
            id_hash=checksum_to_hash(checksum),
            translation__component=component
        ).order_by(*Unit.ordering)
    except ValueError:
        raise Http404('Non existing unit!')
    try:
        source = units[0].source_info
    except IndexError:
        raise Http404('Non existing unit!')

    check_flags = [
        (CHECKS[x].ignore_string, CHECKS[x].name) for x in CHECKS
    ]
    extra_flags = [(x, EXTRA_FLAGS[x]) for x in EXTRA_FLAGS]

    return render(
        request,
        'js/detail.html',
        {
            'units': units,
            'source': source,
            'project': component.project,
            'next': request.GET.get('next', ''),
            'priority_form': PriorityForm(
                initial={'priority': source.priority}
            ),
            'context_form': ContextForm(
                initial={'context': source.context}
            ),

            'check_flags_form': CheckFlagsForm(
                initial={'flags': source.check_flags}
            ),
            'screenshot_form': ScreenshotForm(),
            'extra_flags': extra_flags,
            'check_flags': check_flags,
        }
    )
コード例 #32
0
ファイル: js.py プロジェクト: dekoza/weblate
def get_detail(request, project, component, checksum):
    """Return source translation detail in all languages."""
    component = get_component(request, project, component)
    try:
        units = Unit.objects.filter(
            id_hash=checksum_to_hash(checksum),
            translation__component=component
        )
    except ValueError:
        raise Http404('Non existing unit!')
    try:
        source = units[0].source_info
    except IndexError:
        raise Http404('Non existing unit!')

    check_flags = [
        (CHECKS[x].ignore_string, CHECKS[x].name) for x in CHECKS
    ]
    extra_flags = [(x, EXTRA_FLAGS[x]) for x in EXTRA_FLAGS]

    return render(
        request,
        'js/detail.html',
        {
            'units': units,
            'source': source,
            'project': component.project,
            'next': request.GET.get('next', ''),
            'priority_form': PriorityForm(
                initial={'priority': source.priority}
            ),
            'context_form': ContextForm(
                initial={'context': source.context}
            ),

            'check_flags_form': CheckFlagsForm(
                initial={'flags': source.check_flags}
            ),
            'screenshot_form': ScreenshotForm(),
            'extra_flags': extra_flags,
            'check_flags': check_flags,
        }
    )
コード例 #33
0
ファイル: manage.py プロジェクト: atallahade/weblate
def remove_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.edit', obj):
        raise PermissionDenied()

    form = DeleteForm(obj, request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#delete')

    obj.delete()
    messages.success(request, _('Translation component has been removed.'))
    Change.objects.create(project=obj.project,
                          action=Change.ACTION_REMOVE_COMPONENT,
                          target=obj.slug,
                          user=request.user,
                          author=request.user)

    return redirect(obj.project)
コード例 #34
0
ファイル: settings.py プロジェクト: timgates42/weblate
def change_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("component.edit", obj):
        raise Http404()

    if request.method == "POST":
        form = ComponentSettingsForm(request, request.POST, instance=obj)
        if form.is_valid():
            form.save()
            messages.success(request, _("Settings saved"))
            return redirect("settings",
                            project=obj.project.slug,
                            component=obj.slug)
        else:
            messages.error(
                request,
                _("Invalid settings, please check the form for errors!"))
            # Get a fresh copy of object, otherwise it will use unsaved changes
            # from the failed form
            obj = Component.objects.get(pk=obj.pk)
    else:
        form = ComponentSettingsForm(request, instance=obj)

    if obj.repo_needs_merge():
        messages.warning(
            request,
            _("The repository is outdated, you might not get "
              "expected results until you update it."),
        )

    return render(
        request,
        "component-settings.html",
        {
            "project": obj.project,
            "object": obj,
            "form": form
        },
    )
コード例 #35
0
ファイル: basic.py プロジェクト: dekoza/weblate
def new_language(request, project, component):
    obj = get_component(request, project, component)

    form_class = get_new_language_form(request, obj)

    if request.method == 'POST':
        form = form_class(obj, request.POST)

        if form.is_valid():
            langs = form.cleaned_data['lang']
            for language in Language.objects.filter(code__in=langs):
                if obj.new_lang == 'contact':
                    notify_new_language(obj, language, request.user)
                    messages.success(
                        request,
                        _(
                            "A request for a new translation has been "
                            "sent to the project's maintainers."
                        )
                    )
                elif obj.new_lang == 'add':
                    obj.add_new_language(language, request)
            return redirect(obj)
        else:
            messages.error(
                request,
                _('Please fix errors in the form.')
            )
    else:
        form = form_class(obj)

    return render(
        request,
        'new-language.html',
        {
            'object': obj,
            'project': obj.project,
            'form': form,
        }
    )
コード例 #36
0
ファイル: views.py プロジェクト: dekoza/weblate
def git_export(request, project, component, path):
    """Git HTTP server view.

    Wrapper around git-http-backend to provide Git repositories export over
    HTTP. Performs permission checks and hands over execution to the wrapper.
    """
    # Probably browser access
    if not path:
        return redirect(
            'component',
            project=project,
            component=component,
            permanent=False
        )
    # Strip possible double path separators
    path = path.lstrip('/\\')

    # HTTP authentication
    auth = request.META.get('HTTP_AUTHORIZATION', b'')

    # Reject non pull access early
    if request.GET.get('service', '') not in ('', 'git-upload-pack'):
        raise PermissionDenied('Only pull is supported')

    if auth and not authenticate(request, auth):
        return response_authenticate()

    # Permissions
    try:
        obj = get_component(request, project, component)
    except Http404:
        if not request.user.is_authenticated:
            return response_authenticate()
        raise
    if not request.user.has_perm('vcs.access', obj):
        raise PermissionDenied('No VCS permissions')
    if obj.vcs not in SUPPORTED_VCS:
        raise Http404('Not a git repository')

    return run_git_http(request, obj, path)
コード例 #37
0
def new_language(request, project, component):
    obj = get_component(request, project, component)

    form_class = get_new_language_form(request, obj)

    if request.method == 'POST':
        form = form_class(obj, request.POST)

        if form.is_valid():
            langs = form.cleaned_data['lang']
            for language in Language.objects.filter(code__in=langs):
                if obj.new_lang == 'contact':
                    notify_new_language(obj, language, request.user)
                    messages.success(
                        request,
                        _(
                            "A request for a new translation has been "
                            "sent to the project's maintainers."
                        )
                    )
                elif obj.new_lang == 'add':
                    obj.add_new_language(language, request)
            return redirect(obj)
        else:
            messages.error(
                request,
                _('Please fix errors in the form.')
            )
    else:
        form = form_class(obj)

    return render(
        request,
        'new-language.html',
        {
            'object': obj,
            'project': obj.project,
            'form': form,
        }
    )
コード例 #38
0
ファイル: source.py プロジェクト: nijel/weblate
def matrix_load(request, project, component):
    """Backend for matrix view of all strings"""
    obj = get_component(request, project, component)

    try:
        offset = int(request.GET.get('offset', ''))
    except ValueError:
        return HttpResponseServerError('Missing offset')
    language_codes = request.GET.get('lang')
    if not language_codes or offset is None:
        return HttpResponseServerError('Missing lang')

    # Can not use filter to keep ordering
    translations = [
        get_object_or_404(obj.translation_set, language__code=lang)
        for lang in language_codes.split(',')
    ]

    data = []

    for unit in translations[0].unit_set.all()[offset:offset + 20]:
        units = []
        for translation in translations:
            try:
                units.append(translation.unit_set.get(id_hash=unit.id_hash))
            except Unit.DoesNotExist:
                units.append(None)

        data.append((unit, units))

    return render(
        request,
        'matrix-table.html',
        {
            'object': obj,
            'data': data,
            'last': translations[0].unit_set.count() <= offset + 20
        }
    )
コード例 #39
0
ファイル: source.py プロジェクト: whitemike889/weblate
def matrix_load(request, project, component):
    """Backend for matrix view of all strings."""
    obj = get_component(request, project, component)

    try:
        offset = int(request.GET.get("offset", ""))
    except ValueError:
        return HttpResponseServerError("Missing offset")
    language_codes = request.GET.get("lang")
    if not language_codes or offset is None:
        return HttpResponseServerError("Missing lang")

    # Can not use filter to keep ordering
    translations = [
        get_object_or_404(obj.translation_set, language__code=lang)
        for lang in language_codes.split(",")
    ]

    data = []

    for unit in translations[0].unit_set.all()[offset:offset + 20]:
        units = []
        for translation in translations:
            try:
                units.append(translation.unit_set.get(id_hash=unit.id_hash))
            except Unit.DoesNotExist:
                units.append(None)

        data.append((unit, units))

    return render(
        request,
        "matrix-table.html",
        {
            "object": obj,
            "data": data,
            "last": translations[0].unit_set.count() <= offset + 20,
        },
    )
コード例 #40
0
ファイル: manage.py プロジェクト: dekoza/weblate
def remove_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('component.edit', obj):
        raise PermissionDenied()

    form = DeleteForm(obj, request.POST)
    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#delete')

    obj.delete()
    messages.success(request, _('Translation component has been removed.'))
    Change.objects.create(
        project=obj.project,
        action=Change.ACTION_REMOVE_COMPONENT,
        target=obj.slug,
        user=request.user,
        author=request.user
    )

    return redirect(obj.project)
コード例 #41
0
ファイル: views.py プロジェクト: zzazang/weblate
def show_check_component(request, name, project, component):
    """Show checks failing in a component."""
    component = get_component(request, project, component)
    try:
        check = CHECKS[name]
    except KeyError:
        raise Http404("No check matches the given query.")

    kwargs = {}

    if request.GET.get("lang"):
        kwargs["language__code"] = request.GET["lang"]

    translations = (
        Translation.objects.filter(
            component=component, unit__check__check=name, **kwargs
        )
        .annotate(
            check_count=Count("unit__check"),
            dismissed_check_count=conditional_sum(1, unit__check__dismissed=True),
            active_check_count=conditional_sum(1, unit__check__dismissed=False),
            translated_check_count=conditional_sum(
                1, unit__check__dismissed=False, unit__state__gte=STATE_TRANSLATED
            ),
        )
        .order_by("language__code")
        .select_related("language")
    )

    return render(
        request,
        "check_component.html",
        {
            "translations": translations,
            "title": "{0}/{1}".format(force_str(component), check.name),
            "check": check,
            "component": component,
        },
    )
コード例 #42
0
ファイル: search.py プロジェクト: sarathak/weblate
def parse_url(request, project, component=None, lang=None):
    context = {}
    if component is None:
        obj = get_project(request, project)
        unit_set = Unit.objects.filter(translation__component__project=obj)
        context["project"] = obj
    elif lang is None:
        obj = get_component(request, project, component)
        unit_set = Unit.objects.filter(translation__component=obj)
        context["component"] = obj
        context["project"] = obj.project
    else:
        obj = get_translation(request, project, component, lang)
        unit_set = obj.unit_set.all()
        context["translation"] = obj
        context["component"] = obj.component
        context["project"] = obj.component.project

    if not request.user.has_perm("unit.edit", obj):
        raise PermissionDenied()

    return obj, unit_set, context
コード例 #43
0
def export_stats(request, project, component):
    """Export stats in JSON format."""
    subprj = get_component(request, project, component)
    translations = subprj.translation_set.order_by("language_code")

    return export_response(
        request,
        f"stats-{subprj.project.slug}-{subprj.slug}.csv",
        (
            "name",
            "code",
            "total",
            "translated",
            "translated_percent",
            "translated_words_percent",
            "total_words",
            "translated_words",
            "total_chars",
            "translated_chars",
            "translated_chars_percent",
            "failing",
            "failing_percent",
            "fuzzy",
            "fuzzy_percent",
            "url_translate",
            "url",
            "translate_url",
            "last_change",
            "last_author",
            "recent_changes",
            "readonly",
            "readonly_percent",
            "approved",
            "approved_percent",
            "suggestions",
            "comments",
        ),
        StatisticsSerializer(translations, many=True).data,
    )
コード例 #44
0
ファイル: search.py プロジェクト: dekoza/weblate
def parse_url(request, project, component=None, lang=None):
    context = {}
    if component is None:
        obj = get_project(request, project)
        unit_set = Unit.objects.filter(translation__component__project=obj)
        context['project'] = obj
    elif lang is None:
        obj = get_component(request, project, component)
        unit_set = Unit.objects.filter(translation__component=obj)
        context['component'] = obj
        context['project'] = obj.project
    else:
        obj = get_translation(request, project, component, lang)
        unit_set = obj.unit_set
        context['translation'] = obj
        context['component'] = obj.component
        context['project'] = obj.component.project

    if not request.user.has_perm('unit.edit', obj):
        raise PermissionDenied()

    return obj, unit_set, context
コード例 #45
0
def git_export(request, project, component, path):
    """Git HTTP server view.

    Wrapper around git-http-backend to provide Git repositories export over
    HTTP. Performs permission checks and hands over execution to the wrapper.
    """
    # Probably browser access
    if not path:
        return redirect(
            'component',
            project=project,
            component=component,
            permanent=False
        )
    # Strip possible double path separators
    path = path.lstrip('/\\')

    # HTTP authentication
    auth = request.META.get('HTTP_AUTHORIZATION', b'')

    # Reject non pull access early
    if request.GET.get('service', '') not in ('', 'git-upload-pack'):
        raise PermissionDenied('Only pull is supported')

    if auth and not authenticate(request, auth):
        return response_authenticate()

    # Permissions
    try:
        obj = get_component(request, project, component)
    except Http404:
        if not request.user.is_authenticated:
            return response_authenticate()
        raise
    if not request.user.has_perm('vcs.access', obj):
        raise PermissionDenied('No VCS permissions')

    return run_git_http(request, obj, path)
コード例 #46
0
ファイル: js.py プロジェクト: dekoza/weblate
def git_status_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('meta:vcs.status', obj):
        raise PermissionDenied()

    target = obj
    if target.is_repo_link:
        target = target.linked_component

    return render(
        request,
        'js/git-status.html',
        {
            'object': obj,
            'project': obj.project,
            'changes': Change.objects.filter(
                action__in=Change.ACTIONS_REPOSITORY,
                component=target,
            )[:10],
            'statuses': [(None, obj.repository.status)],
        }
    )
コード例 #47
0
def git_status_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm('meta:vcs.status', obj):
        raise PermissionDenied()

    target = obj
    if target.is_repo_link:
        target = target.linked_component

    return render(
        request,
        'js/git-status.html',
        {
            'object': obj,
            'project': obj.project,
            'changes': Change.objects.filter(
                action__in=Change.ACTIONS_REPOSITORY,
                component=target,
            ).order_by(*Change.ordering)[:10],
            'statuses': [(None, obj.repository.status)],
        }
    )
コード例 #48
0
def watch(request, project, component=None):
    user = request.user
    if component:
        redirect_obj = component_obj = get_component(request, project, component)
        obj = component_obj.project
        # Mute project level subscriptions
        mute_real(user, scope=SCOPE_PROJECT, component=None, project=obj)
        # Manually enable component level subscriptions
        for default_subscription in user.subscription_set.filter(scope=SCOPE_DEFAULT):
            subscription, created = user.subscription_set.get_or_create(
                notification=default_subscription.notification,
                scope=SCOPE_COMPONENT,
                component=component_obj,
                project=None,
                defaults={"frequency": default_subscription.frequency},
            )
            if not created and subscription.frequency != default_subscription.frequency:
                subscription.frequency = default_subscription.frequency
                subscription.save(update_fields=["frequency"])
    else:
        redirect_obj = obj = get_project(request, project)
    user.profile.watched.add(obj)
    return redirect(redirect_obj)
コード例 #49
0
def git_status_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("meta:vcs.status", obj):
        raise PermissionDenied()

    target = obj
    if target.is_repo_link:
        target = target.linked_component

    return render(
        request,
        "js/git-status.html",
        {
            "object": obj,
            "project": obj.project,
            "changes": Change.objects.filter(
                action__in=Change.ACTIONS_REPOSITORY, component=target
            ).order()[:10],
            "statuses": [(None, obj.repository.status)],
            "component": obj,
        },
    )
コード例 #50
0
def change_component(request, project, component):
    obj = get_component(request, project, component)

    if not request.user.has_perm("component.edit", obj):
        raise Http404()

    if request.method == "POST":
        form = ComponentSettingsForm(request, request.POST, instance=obj)
        if form.is_valid():
            form.save()
            messages.success(request, _("Settings saved"))
            return redirect("settings", project=obj.project.slug, component=obj.slug)
        else:
            messages.error(
                request, _("Invalid settings, please check the form for errors!")
            )
    else:
        form = ComponentSettingsForm(request, instance=obj)

    return render(
        request,
        "component-settings.html",
        {"project": obj.project, "object": obj, "form": form},
    )
コード例 #51
0
def show_component(request, project, component):
    obj = get_component(request, project, component)
    user = request.user

    last_changes = Change.objects.prefetch().filter(component=obj)[:10]

    return render(
        request,
        'component.html',
        {
            'allow_index': True,
            'object': obj,
            'project': obj.project,
            'translations': sort_objects(
                prefetch_stats(obj.translation_set.all())
            ),
            'show_language': 1,
            'reports_form': ReportsForm(),
            'last_changes': last_changes,
            'last_changes_url': urlencode(
                {'component': obj.slug, 'project': obj.project.slug}
            ),
            'language_count': Language.objects.filter(
                translation__component=obj
            ).distinct().count(),
            'replace_form': optional_form(ReplaceForm, user, 'unit.edit', obj),
            'mass_state_form': optional_form(
                MassStateForm, user, 'translation.auto', obj,
                user=user, obj=obj
            ),
            'delete_form': optional_form(
                DeleteForm, user, 'component.edit', obj, obj=obj
            ),
            'search_form': SearchForm(),
        }
    )
コード例 #52
0
def export_stats(request, project, component):
    """Export stats in JSON format."""
    subprj = get_component(request, project, component)

    data = [trans.get_stats() for trans in subprj.translation_set.all()]
    return export_response(
        request, 'stats-{0}-{1}.csv'.format(subprj.project.slug, subprj.slug),
        (
            'name',
            'code',
            'total',
            'translated',
            'translated_percent',
            'total_words',
            'translated_words',
            'failing',
            'failing_percent',
            'fuzzy',
            'fuzzy_percent',
            'url_translate',
            'url',
            'last_change',
            'last_author',
        ), data)
コード例 #53
0
ファイル: manage.py プロジェクト: dekoza/weblate
def rename_component(request, project, component):
    obj = get_component(request, project, component)
    return perform_rename(
        ComponentRenameForm, request, obj, 'component.edit',
        component=obj, target=obj.slug, action=Change.ACTION_RENAME_COMPONENT
    )
コード例 #54
0
ファイル: views.py プロジェクト: dekoza/weblate
def show_check_component(request, name, project, component):
    """Show checks failing in a component."""
    subprj = get_component(request, project, component)
    try:
        check = CHECKS[name]
    except KeyError:
        raise Http404('No check matches the given query.')

    ignore = ('ignored' in request.GET)
    url_params = {}

    allchecks = acl_checks(request.user).filter(
        check=name,
        project=subprj.project,
        ignore=ignore,
    )

    if ignore:
        url_params['ignored'] = 'true'

    if check.source:
        url_params['type'] = check.url_id
        return redirect_param(
            'review_source',
            encode_optional(url_params),
            project=subprj.project.slug,
            component=subprj.slug,
        )

    if request.GET.get('language') and '/' not in request.GET['language']:
        url_params['type'] = check.url_id
        return redirect_param(
            'translate',
            encode_optional(url_params),
            project=subprj.project.slug,
            component=subprj.slug,
            lang=request.GET['language'],
        )

    units = Unit.objects.none()

    if check.target:
        langs = allchecks.values_list(
            'language', flat=True
        ).distinct()
        for lang in langs:
            checks = allchecks.filter(
                language=lang,
            ).values_list('content_hash', flat=True)
            res = Unit.objects.filter(
                translation__component=subprj,
                content_hash__in=checks,
                translation__language=lang,
            ).values(
                'translation__language__code'
            ).annotate(count=Count('id'))
            units |= res

    counts = {}
    for unit in units:
        key = unit['translation__language__code']
        if key in counts:
            counts[key] += unit['count']
        else:
            counts[key] = unit['count']

    units = [
        {
            'translation__language__code': item,
            'count': counts[item]
        } for item in counts
    ]

    return render(
        request,
        'check_component.html',
        {
            'checks': units,
            'title': '{0}/{1}'.format(force_text(subprj), check.name),
            'check': check,
            'component': subprj,
            'url_params': encode_optional(url_params),
        }
    )
コード例 #55
0
 def get_object(self, request, project, component):
     return get_component(request, project, component)
コード例 #56
0
ファイル: feeds.py プロジェクト: dekoza/weblate
 def get_object(self, request, project, component):
     return get_component(request, project, component)
コード例 #57
0
ファイル: reports.py プロジェクト: nijel/weblate
def get_credits(request, project, component):
    """View for credits"""
    obj = get_component(request, project, component)

    if not request.user.has_perm('reports.view', obj):
        raise PermissionDenied()

    form = ReportsForm(request.POST)

    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#reports')

    data = generate_credits(
        obj,
        form.cleaned_data['start_date'],
        form.cleaned_data['end_date'],
    )

    if form.cleaned_data['style'] == 'json':
        return JsonResponse(data=data, safe=False)

    if form.cleaned_data['style'] == 'html':
        start = '<table>'
        row_start = '<tr>'
        language_format = '<th>{0}</th>'
        translator_start = '<td><ul>'
        translator_format = '<li><a href="mailto:{0}">{1}</a></li>'
        translator_end = '</ul></td>'
        row_end = '</tr>'
        mime = 'text/html'
        end = '</table>'
    else:
        start = ''
        row_start = ''
        language_format = '* {0}\n'
        translator_start = ''
        translator_format = '    * {1} <{0}>'
        translator_end = ''
        row_end = ''
        mime = 'text/plain'
        end = ''

    result = []

    result.append(start)

    for language in data:
        name, translators = language.popitem()
        result.append(row_start)
        result.append(language_format.format(name))
        result.append(
            ''.join((
                translator_start,
                '\n'.join(
                    [translator_format.format(*t) for t in translators]
                ),
                translator_end,
            ))
        )
        result.append(row_end)

    result.append(end)

    return HttpResponse(
        '\n'.join(result),
        content_type='{0}; charset=utf-8'.format(mime),
    )
コード例 #58
0
ファイル: reports.py プロジェクト: nijel/weblate
def get_counts(request, project, component):
    """View for work counts"""
    obj = get_component(request, project, component)

    if not request.user.has_perm('reports.view', obj):
        raise PermissionDenied()

    form = ReportsForm(request.POST)

    if not form.is_valid():
        show_form_errors(request, form)
        return redirect_param(obj, '#reports')

    data = generate_counts(
        obj,
        form.cleaned_data['start_date'],
        form.cleaned_data['end_date'],
    )

    if form.cleaned_data['style'] == 'json':
        return JsonResponse(data=data, safe=False)

    headers = (
        'Name',
        'Email',
        'Count total',
        'Source words total',
        'Source chars total',
        'Target words total',
        'Target chars total',

        'Count new',
        'Source words new',
        'Source chars new',
        'Target words new',
        'Target chars new',

        'Count approved',
        'Source words approved',
        'Source chars approved',
        'Target words approved',
        'Target chars approved',

        'Count edited',
        'Source words edited',
        'Source chars edited',
        'Target words edited',
        'Target chars edited',
    )

    if form.cleaned_data['style'] == 'html':
        start = HTML_HEADING.format(
            ''.join(['<th>{0}</th>'.format(h) for h in headers])
        )
        row_start = '<tr>'
        cell_name = cell_count = '<td>{0}</td>\n'
        row_end = '</tr>'
        mime = 'text/html'
        end = '</table>'
    else:
        start = '{0}\n{1} {2}\n{0}'.format(
            RST_HEADING,
            ' '.join(['{0:40}'.format(h) for h in headers[:2]]),
            ' '.join(['{0:24}'.format(h) for h in headers[2:]]),
        )
        row_start = ''
        cell_name = '{0:40} '
        cell_count = '{0:24} '
        row_end = ''
        mime = 'text/plain'
        end = RST_HEADING

    result = []

    result.append(start)

    for item in data:
        if row_start:
            result.append(row_start)
        result.append(
            ''.join((
                cell_name.format(item['name']),
                cell_name.format(item['email']),

                cell_count.format(item['count']),
                cell_count.format(item['words']),
                cell_count.format(item['chars']),
                cell_count.format(item['t_words']),
                cell_count.format(item['t_chars']),

                cell_count.format(item['count_new']),
                cell_count.format(item['words_new']),
                cell_count.format(item['chars_new']),
                cell_count.format(item['t_words_new']),
                cell_count.format(item['t_chars_new']),

                cell_count.format(item['count_approve']),
                cell_count.format(item['words_approve']),
                cell_count.format(item['chars_approve']),
                cell_count.format(item['t_words_approve']),
                cell_count.format(item['t_chars_approve']),

                cell_count.format(item['count_edit']),
                cell_count.format(item['words_edit']),
                cell_count.format(item['chars_edit']),
                cell_count.format(item['t_words_edit']),
                cell_count.format(item['t_chars_edit']),
            ))
        )
        if row_end:
            result.append(row_end)

    result.append(end)

    return HttpResponse(
        '\n'.join(result),
        content_type='{0}; charset=utf-8'.format(mime),
    )
コード例 #59
0
def mute_component(request, project, component):
    obj = get_component(request, project, component)
    mute_real(request.user, scope=SCOPE_COMPONENT, component=obj, project=None)
    return redirect('{}?notify_component={}#notifications'.format(
        reverse('profile'), obj.pk))
コード例 #60
0
ファイル: search.py プロジェクト: dekoza/weblate
def search(request, project=None, component=None, lang=None):
    """Perform site-wide search on units."""
    is_ratelimited = not check_rate_limit('search', request)
    search_form = SiteSearchForm(request.GET)
    context = {
        'search_form': search_form,
    }
    search_kwargs = {}
    if component:
        obj = get_component(request, project, component)
        context['component'] = obj
        context['project'] = obj.project
        context['back_url'] = obj.get_absolute_url()
        search_kwargs = {'component': obj}
    elif project:
        obj = get_project(request, project)
        context['project'] = obj
        context['back_url'] = obj.get_absolute_url()
        search_kwargs = {'project': obj}
    else:
        obj = None
        context['back_url'] = None
    if lang:
        s_language = get_object_or_404(Language, code=lang)
        context['language'] = s_language
        search_kwargs = {'language': s_language}
        if obj:
            if component:
                context['back_url'] = obj.translation_set.get(
                    language=s_language
                ).get_absolute_url()
            else:
                context['back_url'] = reverse(
                    'project-language',
                    kwargs={
                        'project': project,
                        'lang': lang,
                    }
                )
        else:
            context['back_url'] = s_language.get_absolute_url()

    if not is_ratelimited and request.GET and search_form.is_valid():
        # Filter results by ACL
        if component:
            units = Unit.objects.filter(translation__component=obj)
        elif project:
            units = Unit.objects.filter(translation__component__project=obj)
        else:
            allowed_projects = request.user.allowed_projects
            units = Unit.objects.filter(
                translation__component__project__in=allowed_projects
            )
        units = units.search(
            search_form.cleaned_data,
            **search_kwargs
        )
        if lang:
            units = units.filter(
                translation__language=context['language']
            )

        units = get_paginator(request, units)

        context['show_results'] = True
        context['page_obj'] = units
        context['title'] = _('Search for %s') % (
            search_form.cleaned_data['q']
        )
        context['query_string'] = search_form.urlencode()
        context['search_query'] = search_form.cleaned_data['q']
    elif is_ratelimited:
        messages.error(
            request, _('Too many search queries, please try again later.')
        )
    elif request.GET:
        messages.error(request, _('Invalid search query!'))
        show_form_errors(request, search_form)

    return render(
        request,
        'search.html',
        context
    )