From 433690248edc4689d446220de112ba326e42a240 Mon Sep 17 00:00:00 2001 From: Sergei Date: Mon, 20 May 2024 19:20:23 +0300 Subject: [PATCH 1/4] add only_staff filter to leaderboard pages --- contributors/forms/forms.py | 17 ++++++++++++++--- contributors/views/leaderboard_commits.py | 3 +++ contributors/views/leaderboard_issues.py | 3 +++ contributors/views/leaderboard_prs.py | 3 +++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/contributors/forms/forms.py b/contributors/forms/forms.py index 031d365a..cd861007 100644 --- a/contributors/forms/forms.py +++ b/contributors/forms/forms.py @@ -1,6 +1,6 @@ from crispy_forms.bootstrap import FieldWithButtons, StrictButton from crispy_forms.helper import FormHelper -from crispy_forms.layout import Field, Layout +from crispy_forms.layout import Div, Field, Layout from django import forms from django.utils.translation import gettext_lazy as _ @@ -49,6 +49,11 @@ class CombinedSearchForm(TableSortSearchForm): help_text=_("Exact match required for this field"), ) + is_hexlet_stuff = forms.BooleanField( + required=False, + label=_('is_hexlet_stuff'), + ) + @property def helper(self): """Control form attributes and its layout.""" @@ -56,10 +61,16 @@ def helper(self): helper.form_method = 'get' helper.form_class = 'd-flex' helper.layout = Layout( - Field('search', placeholder=_("Filter by name")), + Div( + Field('search', placeholder=_("Filter by name")), + Div( + Field('is_hexlet_stuff'), + ), + ), FieldWithButtons( Field( - 'organizations', placeholder=_("Filter by organization"), + 'organizations', + placeholder=_("Filter by organization"), ), StrictButton( _("Search"), diff --git a/contributors/views/leaderboard_commits.py b/contributors/views/leaderboard_commits.py index d6233c7f..4b365e78 100644 --- a/contributors/views/leaderboard_commits.py +++ b/contributors/views/leaderboard_commits.py @@ -37,4 +37,7 @@ def get_queryset(self): # noqa: WPS615 queryset = queryset.filter( contributors__organization__name__exact=organizations, ) + is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] + if is_hexlet_stuff: + queryset = queryset.filter(user__is_staff=True) return queryset diff --git a/contributors/views/leaderboard_issues.py b/contributors/views/leaderboard_issues.py index f8180bad..95cc38e4 100644 --- a/contributors/views/leaderboard_issues.py +++ b/contributors/views/leaderboard_issues.py @@ -37,4 +37,7 @@ def get_queryset(self): # noqa: WPS615 queryset = queryset.filter( contributors__organization__name__exact=organizations, ) + is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] + if is_hexlet_stuff: + queryset = queryset.filter(user__is_staff=True) return queryset diff --git a/contributors/views/leaderboard_prs.py b/contributors/views/leaderboard_prs.py index 638d69d4..f5bc3b8f 100644 --- a/contributors/views/leaderboard_prs.py +++ b/contributors/views/leaderboard_prs.py @@ -38,4 +38,7 @@ def get_queryset(self): # noqa: WPS615 queryset = queryset.filter( contributors__organization__name__exact=organizations, ) + is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] + if is_hexlet_stuff: + queryset = queryset.filter(user__is_staff=True) return queryset From b106cee5e4af4b56c1d58013594d69a794d045a0 Mon Sep 17 00:00:00 2001 From: Sergei Date: Mon, 20 May 2024 20:03:51 +0300 Subject: [PATCH 2/4] remove new filter from pages that are not leaderboard --- contributors/forms/forms.py | 32 +++++++++++++++++++++++ contributors/views/leaderboard_commits.py | 6 ++--- contributors/views/leaderboard_issues.py | 6 ++--- contributors/views/leaderboard_prs.py | 6 ++--- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/contributors/forms/forms.py b/contributors/forms/forms.py index cd861007..38a6e321 100644 --- a/contributors/forms/forms.py +++ b/contributors/forms/forms.py @@ -49,6 +49,38 @@ class CombinedSearchForm(TableSortSearchForm): help_text=_("Exact match required for this field"), ) + @property + def helper(self): + """Control form attributes and its layout.""" + helper = FormHelper() + helper.form_method = 'get' + helper.form_class = 'd-flex' + helper.layout = Layout( + Field('search', placeholder=_("Filter by name")), + FieldWithButtons( + Field( + 'organizations', placeholder=_("Filter by organization"), + ), + StrictButton( + _("Search"), + type='submit', + css_class='btn btn-outline-primary', + ), + ), + ) + return helper + + +class LeaderboardCombinedSearchForm(TableSortSearchForm): + """Search form of contributors by organization.""" + + organizations = forms.CharField( + label=False, + required=False, + widget=forms.TextInput(), + help_text=_("Exact match required for this field"), + ) + is_hexlet_stuff = forms.BooleanField( required=False, label=_('is_hexlet_stuff'), diff --git a/contributors/views/leaderboard_commits.py b/contributors/views/leaderboard_commits.py index 4b365e78..e273a401 100644 --- a/contributors/views/leaderboard_commits.py +++ b/contributors/views/leaderboard_commits.py @@ -1,6 +1,6 @@ from django.views import generic -from contributors.forms.forms import CombinedSearchForm +from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor from contributors.views.mixins import TableSortSearchAndPaginationMixin @@ -22,7 +22,7 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): def get_context_data(self, **kwargs): """Get search form by organizations.""" context = super().get_context_data(**kwargs) - context['form_org'] = CombinedSearchForm(self.request.GET) + context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) return context def get_queryset(self): # noqa: WPS615 @@ -30,7 +30,7 @@ def get_queryset(self): # noqa: WPS615 queryset = super().get_queryset().prefetch_related( 'contributors__organization', ) - form = CombinedSearchForm(self.request.GET) + form = LeaderboardCombinedSearchForm(self.request.GET) if form.is_valid(): organizations = form.cleaned_data['organizations'] if organizations: diff --git a/contributors/views/leaderboard_issues.py b/contributors/views/leaderboard_issues.py index 95cc38e4..000fac1f 100644 --- a/contributors/views/leaderboard_issues.py +++ b/contributors/views/leaderboard_issues.py @@ -1,6 +1,6 @@ from django.views import generic -from contributors.forms.forms import CombinedSearchForm +from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor from contributors.views.mixins import TableSortSearchAndPaginationMixin @@ -22,7 +22,7 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): def get_context_data(self, **kwargs): """Get search form by organizations.""" context = super().get_context_data(**kwargs) - context['form_org'] = CombinedSearchForm(self.request.GET) + context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) return context def get_queryset(self): # noqa: WPS615 @@ -30,7 +30,7 @@ def get_queryset(self): # noqa: WPS615 queryset = super().get_queryset().prefetch_related( 'contributors__organization', ) - form = CombinedSearchForm(self.request.GET) + form = LeaderboardCombinedSearchForm(self.request.GET) if form.is_valid(): organizations = form.cleaned_data['organizations'] if organizations: diff --git a/contributors/views/leaderboard_prs.py b/contributors/views/leaderboard_prs.py index f5bc3b8f..e219b2fc 100644 --- a/contributors/views/leaderboard_prs.py +++ b/contributors/views/leaderboard_prs.py @@ -1,6 +1,6 @@ from django.views import generic -from contributors.forms.forms import CombinedSearchForm +from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor from contributors.views.mixins import TableSortSearchAndPaginationMixin @@ -23,7 +23,7 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): def get_context_data(self, **kwargs): """Get search form by organizations.""" context = super().get_context_data(**kwargs) - context['form_org'] = CombinedSearchForm(self.request.GET) + context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) return context def get_queryset(self): # noqa: WPS615 @@ -31,7 +31,7 @@ def get_queryset(self): # noqa: WPS615 queryset = super().get_queryset().prefetch_related( 'contributors__organization', ) - form = CombinedSearchForm(self.request.GET) + form = LeaderboardCombinedSearchForm(self.request.GET) if form.is_valid(): organizations = form.cleaned_data['organizations'] if organizations: From 750a6fe2861bd9fa20888c632142b59a5194e2d1 Mon Sep 17 00:00:00 2001 From: Sergei Date: Thu, 23 May 2024 14:09:59 +0300 Subject: [PATCH 3/4] change new filter from CheckboxSelectMultiple to ChoiceField, move code from leaderboad views to mixin in mixins.py --- contributors/forms/__init__.py | 1 - contributors/forms/forms.py | 19 ++++++------ contributors/views/leaderboard_commits.py | 35 ++++++----------------- contributors/views/leaderboard_issues.py | 35 ++++++----------------- contributors/views/leaderboard_prs.py | 35 ++++++----------------- contributors/views/mixins.py | 34 +++++++++++++++++++++- 6 files changed, 70 insertions(+), 89 deletions(-) diff --git a/contributors/forms/__init__.py b/contributors/forms/__init__.py index d30e5cc7..63d84655 100644 --- a/contributors/forms/__init__.py +++ b/contributors/forms/__init__.py @@ -1,2 +1 @@ from contributors.forms.admin_forms import OrgNamesForm, RepoNamesForm -from contributors.forms.forms import TableSortSearchForm diff --git a/contributors/forms/forms.py b/contributors/forms/forms.py index 38a6e321..86afa804 100644 --- a/contributors/forms/forms.py +++ b/contributors/forms/forms.py @@ -1,6 +1,6 @@ from crispy_forms.bootstrap import FieldWithButtons, StrictButton from crispy_forms.helper import FormHelper -from crispy_forms.layout import Div, Field, Layout +from crispy_forms.layout import Field, Layout from django import forms from django.utils.translation import gettext_lazy as _ @@ -81,9 +81,14 @@ class LeaderboardCombinedSearchForm(TableSortSearchForm): help_text=_("Exact match required for this field"), ) - is_hexlet_stuff = forms.BooleanField( + sample = forms.ChoiceField( required=False, - label=_('is_hexlet_stuff'), + label='', + choices=( + ('all', 'Все пользователи'), + ('except_staff', 'Кроме сотрудников'), + ('only_staff', 'Только сотрудники'), + ), ) @property @@ -93,12 +98,8 @@ def helper(self): helper.form_method = 'get' helper.form_class = 'd-flex' helper.layout = Layout( - Div( - Field('search', placeholder=_("Filter by name")), - Div( - Field('is_hexlet_stuff'), - ), - ), + Field('sample', placeholder='Sample'), + Field('search', placeholder=_("Filter by name")), FieldWithButtons( Field( 'organizations', diff --git a/contributors/views/leaderboard_commits.py b/contributors/views/leaderboard_commits.py index e273a401..08f3b5d6 100644 --- a/contributors/views/leaderboard_commits.py +++ b/contributors/views/leaderboard_commits.py @@ -1,11 +1,17 @@ from django.views import generic -from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor -from contributors.views.mixins import TableSortSearchAndPaginationMixin +from contributors.views.mixins import ( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, +) -class ListView(TableSortSearchAndPaginationMixin, generic.ListView): +class ListView( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, + generic.ListView, +): """List of leaders among contributors by commits.""" queryset = Contributor.objects.visible().with_contributions() @@ -18,26 +24,3 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): searchable_fields = ('login', 'name') ordering = sortable_fields[0] paginate_by = 100 - - def get_context_data(self, **kwargs): - """Get search form by organizations.""" - context = super().get_context_data(**kwargs) - context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) - return context - - def get_queryset(self): # noqa: WPS615 - """Get filter queryset.""" - queryset = super().get_queryset().prefetch_related( - 'contributors__organization', - ) - form = LeaderboardCombinedSearchForm(self.request.GET) - if form.is_valid(): - organizations = form.cleaned_data['organizations'] - if organizations: - queryset = queryset.filter( - contributors__organization__name__exact=organizations, - ) - is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] - if is_hexlet_stuff: - queryset = queryset.filter(user__is_staff=True) - return queryset diff --git a/contributors/views/leaderboard_issues.py b/contributors/views/leaderboard_issues.py index 000fac1f..f2c886a7 100644 --- a/contributors/views/leaderboard_issues.py +++ b/contributors/views/leaderboard_issues.py @@ -1,11 +1,17 @@ from django.views import generic -from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor -from contributors.views.mixins import TableSortSearchAndPaginationMixin +from contributors.views.mixins import ( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, +) -class ListView(TableSortSearchAndPaginationMixin, generic.ListView): +class ListView( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, + generic.ListView, +): """List of leaders among contributors by issues.""" queryset = Contributor.objects.visible().with_contributions() @@ -18,26 +24,3 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): searchable_fields = ('login', 'name') ordering = sortable_fields[0] paginate_by = 100 - - def get_context_data(self, **kwargs): - """Get search form by organizations.""" - context = super().get_context_data(**kwargs) - context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) - return context - - def get_queryset(self): # noqa: WPS615 - """Get filter queryset.""" - queryset = super().get_queryset().prefetch_related( - 'contributors__organization', - ) - form = LeaderboardCombinedSearchForm(self.request.GET) - if form.is_valid(): - organizations = form.cleaned_data['organizations'] - if organizations: - queryset = queryset.filter( - contributors__organization__name__exact=organizations, - ) - is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] - if is_hexlet_stuff: - queryset = queryset.filter(user__is_staff=True) - return queryset diff --git a/contributors/views/leaderboard_prs.py b/contributors/views/leaderboard_prs.py index e219b2fc..8fea8e01 100644 --- a/contributors/views/leaderboard_prs.py +++ b/contributors/views/leaderboard_prs.py @@ -1,11 +1,17 @@ from django.views import generic -from contributors.forms.forms import LeaderboardCombinedSearchForm from contributors.models import Contributor -from contributors.views.mixins import TableSortSearchAndPaginationMixin +from contributors.views.mixins import ( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, +) -class ListView(TableSortSearchAndPaginationMixin, generic.ListView): +class ListView( + LeaderboardQueryMixin, + TableSortSearchAndPaginationMixin, + generic.ListView, +): """List of leaders among contributors by pull requests.""" queryset = Contributor.objects.visible().with_contributions() @@ -19,26 +25,3 @@ class ListView(TableSortSearchAndPaginationMixin, generic.ListView): searchable_fields = ('login', 'name') ordering = sortable_fields[0] paginate_by = 100 - - def get_context_data(self, **kwargs): - """Get search form by organizations.""" - context = super().get_context_data(**kwargs) - context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) - return context - - def get_queryset(self): # noqa: WPS615 - """Get filter queryset.""" - queryset = super().get_queryset().prefetch_related( - 'contributors__organization', - ) - form = LeaderboardCombinedSearchForm(self.request.GET) - if form.is_valid(): - organizations = form.cleaned_data['organizations'] - if organizations: - queryset = queryset.filter( - contributors__organization__name__exact=organizations, - ) - is_hexlet_stuff = form.cleaned_data['is_hexlet_stuff'] - if is_hexlet_stuff: - queryset = queryset.filter(user__is_staff=True) - return queryset diff --git a/contributors/views/mixins.py b/contributors/views/mixins.py index 8268f3af..4cdfbc62 100644 --- a/contributors/views/mixins.py +++ b/contributors/views/mixins.py @@ -10,7 +10,10 @@ from django.views.generic.list import MultipleObjectMixin from django_cte import With -from contributors.forms import TableSortSearchForm +from contributors.forms.forms import ( + LeaderboardCombinedSearchForm, + TableSortSearchForm, +) from contributors.utils.misc import DIRECTION_TRANSLATIONS, split_ordering MAX_PAGES_WITHOUT_SHRINKING = 7 @@ -245,3 +248,32 @@ def handle_no_permission(self): """Redirect user without permissions.""" messages.warning(self.request, self.no_permission_msg) return redirect(self.redirect_url) + + +class LeaderboardQueryMixin(MultipleObjectMixin): + """A mixin for custom queries in leaderboard views.""" + + def get_context_data(self, **kwargs): + """Get search form by organizations.""" + context = super().get_context_data(**kwargs) + context['form_org'] = LeaderboardCombinedSearchForm(self.request.GET) + return context + + def get_queryset(self): # noqa: WPS615 + """Get filter queryset.""" + queryset = super().get_queryset().prefetch_related( + 'contributors__organization', + ) + form = LeaderboardCombinedSearchForm(self.request.GET) + if form.is_valid(): + organizations = form.cleaned_data['organizations'] + if organizations: + queryset = queryset.filter( + contributors__organization__name__exact=organizations, + ) + sample = form.cleaned_data['sample'] + if sample == 'except_staff': + queryset = queryset.exclude(user__is_staff=True) + elif sample == 'only_staff': + queryset = queryset.filter(user__is_staff=True) + return queryset From a770a01c83fd3691567af33a817157dd9d79b468 Mon Sep 17 00:00:00 2001 From: Sergei Date: Tue, 28 May 2024 20:07:26 +0300 Subject: [PATCH 4/4] add i18n for new filter --- contributors/forms/forms.py | 6 +++--- locale/ru/LC_MESSAGES/django.mo | Bin 12481 -> 12663 bytes locale/ru/LC_MESSAGES/django.po | 14 +++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contributors/forms/forms.py b/contributors/forms/forms.py index 86afa804..fe35a541 100644 --- a/contributors/forms/forms.py +++ b/contributors/forms/forms.py @@ -85,9 +85,9 @@ class LeaderboardCombinedSearchForm(TableSortSearchForm): required=False, label='', choices=( - ('all', 'Все пользователи'), - ('except_staff', 'Кроме сотрудников'), - ('only_staff', 'Только сотрудники'), + ('all', _('All users')), + ('except_staff', _('Except staff')), + ('only_staff', _('Only staff')), ), ) diff --git a/locale/ru/LC_MESSAGES/django.mo b/locale/ru/LC_MESSAGES/django.mo index 1bf8dc7c8e3fbeb040e3dc999d470485da198ace..90159eb01c84eb3af3b3bd6947ef7c530df9c50c 100644 GIT binary patch delta 3723 zcmZwJX>g5K9LMn!i4d|85nJoFA+{ivM70R1eOKC`p+rP+35lq*rhU;f{`Ygvx#v0ibK~^XN9n#B4TH8A zQVG$5=vCX8o0wLQ57M_`#suJ1%*N};KQl7im^zq-p_qYzI3GhW7h}+ebZNHQ`kh#p z@~7CCugxJcu~eMH9$16H7#m?s5Vl8^J7a51!Zw(O>S#G?BI__3x1c6)0PAA~YJ#Vc z0nJ5JyPq(O@y(yMK}e*#vc}d{sDZkoI-H12FavwyV${SdQ3G5@P3ShV2J;JQK-0jO zMi7HknRwLZ_Ewqk&0sRj!AwAPG!vi0g{T3yp&ls3hj;=Lv8*A_;BC}^DN*hKV^IC1 zqjoL}wSa}FcKN7@Za|;5Xd4+dEJ1DM0o0k5qXs^TI`b;jk$i=WX|CAv9aP8nQSF|f zo(pB!nn(<)z7?unS5*J~8nOTCXb=_8;zZQU@=z;ZiaM(usEL)LF6mKJyKhh(-$ZTg zJ=6eCkWDgSJgjytQ4?uvO+-yFC7S)$){mea&ivau89p*q@!+Obm9#80By z`H_F-3Lom{9HdbtS6f zGq%3k*55!);I94tcl&)U&QbLds2yvHI+}Q7T%YOVX3QW|!_lZ6n21`*6x76KTeDF+ zm4|A#1T~@Mwtgcz3qVbH531cE)QS(I7JLdr_5PnDqlRBQ6~_F48u&iy!N*q9)a@V` zHGyzjj=~H4L^enLQr>Q6%rU%!TInav-8)r@+)Hy7bp+S3q2B+yWLn|hsDWE?#dS$K zBgbn-p?(iCaUib3nRp4+zUMP+EA~fqJQ*ir7LLb@sD9dTadf%+pzhEJK72Y8FBv`P zLzOq;^SBo^v9ri=ni|xK0-2o#jJ9^hF_ed(2H1hRtoyM5zr&aD4UfB!z1W)a84vrf z0cxm7z(|%U`(azmMh&=)+W|irf1)oQay)9MsO1 zpzc5=dhmjejAnEXbw&{^Q^uh>?2Ve(1k_4rVKNq>I=Y7XBXl1-U=-V?i6&zo9F97Y zHK-#jLavP|L)K(`mu%)CdZ=jL&YeIn>sae7*&%|(C zjhgs&)b}N*ohn5Q_$BJCxs2g>ADzGdPsliD&jE8`O`LTI>h17aH=!nU81={HGHQUI zQAhFEmSYp#iF8LzB-xgSTT?NZ`gGLaA2XAT%*ROFih6J#YNi#aovA|Y%r#W|U#%fs z+!cB-lKO6_BkGSDXp;Rt0|O|lZUjN{IcK%QEtm|9C%nXBVlT0WP%0$U=`Mm(GcOS@ z5?zV62&G{zW((@BXc3&ESwt|llM?wXCT0*T)zf=UHNQ?)ZFy~C458x~MI;fm2zJ;> z{rT)m=+#wvo2cXD+#Sm!Uu4T;t-8$lHXnkUiC46eG(ta*O5+GFu#kC^!X-8@J|LzL%ZU_X zA))jk(T^BNyh@ZfvV{f6TW*HyBvWnW$5zpk=x)nlIF*=1yid#|^vkHE zTd$-`snmvOKny0biPs4a@eZN1+Qs?o;e4|HE69`(vBXFsnwUTgASM#i2)%A`#5N+6 z7)?A)L1dZ{<86iBfZjwqVm*U__r1Yv}j!ZuzBwwPf>Ng|CIlP zzrsU{Q`JkW^Q)KnKlh*XAMqdKi?Z?rPy1lc9KE~n%RL66$IW9sCY!#}* zEvWnUq9$;{zwSAA+A7YOzo0t$6V+g1z`3^A6|*rH8M!M*&8Qj~o7;ox=sj$WXOKVl z6CYa4Kdc?1AcNH0ptw*nnl&2TNj{8;{kf4sW75h-ej@X?xTP zrlAJj19e|EYM{eVD>E8(Um<#0!s%qRN2REa=c1OV9JLjzk-pppE7zbJ-i^BNUDQ&4 zWaT=${sXGr-%!stU_6GiJQ`4HYxZ9=?n#CAW;kjS!%$#ye00*oQ2R zdmq){=cs{vZC*r8=qhT-Z=wd&oX+%o%UIT5OOZ%L2BxAK8jD)0$*7T+pzd3O{J9l; zsG%Lmq+B)Xxx-ff0VYuX5Y=%#YT(yUD;mZ@(en`=8C3*OhbNYgEKEl&)nx32OE44P zLG5ilYGzkZ1O3a&VZ3v?9zb>24z;4)Py_6Rn#cguN_n|pq9D_)$ly4_pE*m zs)H)KzRRv3wEE+y6+4OAn(t5@Up5<1&;O0Afak(F0GdfOYGiR{B5Gw)QA?GM8c>$i z=b&bgiyCkq>b^mf@&=5cf47s29^7pnKs9g(HGpGQK7ptBD*OcX zjab>vxuduZHPig|!9!JqoHI8cwFMQZ6{*5x+>e@Y9k$W?f1Zrq|7$oD+i>(}U?J+p zlNg6}s0J_NB)p9UIPvb_**T0l)u&Kr=Pat@8>r`^s8l%~lQ0uKjc5!Rw!ETg=O@8N1}$1JFF$FMtIKusW$(P-wKQSJ9LN21Qg zv=lFRI7+F|QZF=@o9mHXaaHCK)FG`y4eVRgk_I{l_q-D(Qtpquk#4*>8`aJ#)PQPG z6FlUR8Azrcb!d`V4*j@fV>c{Bo!$z}!AjH?e1+PwdgK_mTgX^k9P29wVj>oy2C~xJ zX&yq3h4VfmqY+&~{@e{dv=W`V@Je9@YK9)F!%e6T_MirK2HAFZ9@WlmsL@Syou^CG9!4%5>WSNqplA_ zfA3MR*=%z&>TNq>p2c|j_fLX;L=rd=YM>WtD+XJ67HS|%Py?;7a-~^~O{m|8>bTbY z6xH63sONsiX#5AYGSNL*e=SWi89g|_%ty^|CI+w^wMFYt9leRVegH#Ibt4F+QevB* zb8ZTBNh~azbfh5PwU<$Uj1KBpxPu6OD-O`udi94yOWukBa@rsr6%*V0Z^38BP zF^U*Z3?h_tfO#SOq(iAyoE0qkTiVk4cN45K6ZJkTO(nMbx&J=qTJ}MFfzUqwKdHT! zh$14~F1&0G!9|uA8wpSETK#TDy0wsKNtKCC?KCeJZE*QOwq^k%dnbAA|4|2 zT{4!)CB_j?5HSQ_CvL0ue;S#Q#GMpMMn4{pSw#!Hmq;a66ZymnVhd48Boj{)?TIR) z6`@o@R1i<8K)R1uLab4NG=Rv^htfKtF_EqUX*RLe&+$K?xf2&!UPN#HBI\n" "Language-Team: LANGUAGE \n" @@ -85,6 +85,18 @@ msgstr "Введите точное название организации" msgid "Filter by organization" msgstr "Фильтрация по организации" +#: contributors/forms/forms.py +msgid "All users" +msgstr "Все пользователи" + +#: contributors/forms/forms.py +msgid "Except staff" +msgstr "Кроме сотрудников" + +#: contributors/forms/forms.py +msgid "Only staff" +msgstr "Только сотрудники" + #: contributors/forms/forms.py msgid "Filter by status" msgstr "Фильтрация по статусу"