0001-migrate-to-Django-Select2-5-fixes-15604.patch
setup.py | ||
---|---|---|
114 | 114 |
'django-model-utils>=2.4', |
115 | 115 |
'django-admin-tools>=0.6,<0.7', |
116 | 116 |
'dnspython>=1.10', |
117 |
'Django-Select2>=4.3.0,<5',
|
|
117 |
'Django-Select2>5', |
|
118 | 118 |
'django-tables2>=1.0,<1.1', |
119 | 119 |
'gadjo', |
120 | 120 |
'django-import-export>=0.2.7', |
... | ... | |
131 | 131 |
'cryptography', |
132 | 132 |
'XStatic-jQuery', |
133 | 133 |
'XStatic-jquery-ui', |
134 |
'xstatic-select2', |
|
134 | 135 |
], |
135 | 136 |
extras_require = { |
136 | 137 |
'idp-openid': ['python-openid'], |
src/authentic2/manager/fields.py | ||
---|---|---|
1 |
from django_select2 import AutoModelSelect2Field, \ |
|
2 |
AutoModelSelect2MultipleField, NO_ERR_RESP |
|
1 |
from django import forms |
|
3 | 2 | |
4 |
from django.contrib.auth.models import Group, Permission |
|
5 |
from django.contrib.auth import get_user_model |
|
6 |
from django.db.models.query import Q |
|
3 |
from . import widgets |
|
7 | 4 | |
8 |
from django_rbac.backends import DjangoRBACBackend |
|
9 |
from django_rbac.utils import get_role_model, get_ou_model |
|
10 | 5 | |
11 |
from authentic2.models import Service |
|
12 | ||
13 |
from . import utils |
|
14 | ||
15 | ||
16 |
class SecurityCheckMixin(object): |
|
17 |
operations = ['change', 'add', 'view', 'delete'] |
|
18 | ||
19 |
@property |
|
20 |
def perms(self): |
|
21 |
model = self.queryset.model |
|
22 |
app_label = model._meta.app_label |
|
23 |
model_name = model._meta.model_name |
|
24 |
return ['%s.%s_%s' % (app_label, perm, model_name) |
|
25 |
for perm in self.operations] |
|
26 | ||
27 |
def security_check(self, request, *args, **kwargs): |
|
28 |
model = self.queryset.model |
|
29 |
app_label = model._meta.app_label |
|
30 |
model_name = model._meta.model_name |
|
31 |
return request.user.is_authenticated() \ |
|
32 |
and request.user.has_perm_any(self.perms) |
|
33 | ||
34 |
def prepare_qs_params(self, request, search_term, search_fields): |
|
35 |
'''Only search visible objects''' |
|
36 |
ors = [] |
|
37 |
ands = {} |
|
38 |
for term in search_term.split(): |
|
39 |
qs_params = super(SecurityCheckMixin, self).prepare_qs_params( |
|
40 |
request, term, search_fields) |
|
41 |
ors.extend(qs_params['or']) |
|
42 |
ands.update(qs_params['and']) |
|
43 |
model = self.queryset.model |
|
44 |
app_label = model._meta.app_label |
|
45 |
model_name = model._meta.model_name |
|
46 |
rbac_backend = DjangoRBACBackend() |
|
47 |
query = rbac_backend.filter_by_perm_query( |
|
48 |
request.user, self.perms, self.queryset) |
|
49 |
if query is False: |
|
50 |
ands['id'] = -1 |
|
51 |
elif query is True: |
|
52 |
pass |
|
6 |
class Select2Mixin(object): |
|
7 |
def __init__(self, **kwargs): |
|
8 |
if getattr(self.widget, 'queryset', None) is not None: |
|
9 |
kwargs['queryset'] = self.widget.queryset |
|
10 |
elif getattr(self.widget, 'model', None): |
|
11 |
kwargs['queryset'] = self.widget.model.objects.all() |
|
53 | 12 |
else: |
54 |
ors = [query & reduce(Q.__or__, ors)] |
|
55 |
return {'or': ors, 'and': ands} |
|
56 | ||
57 | ||
58 |
class SplitSearchTermMixin(object): |
|
59 |
def prepare_qs_params(self, request, search_term, search_fields): |
|
60 |
ors = [] |
|
61 |
ands = {} |
|
62 |
for term in search_term.split(): |
|
63 |
qs_params = super(SplitSearchTermMixin, self).prepare_qs_params( |
|
64 |
request, term, search_fields) |
|
65 |
ors.extend(qs_params['or']) |
|
66 |
ands.update(qs_params['and']) |
|
67 |
return {'or': ors, 'and': ands} |
|
68 | ||
69 | ||
70 |
class ChooseUserField(SecurityCheckMixin, SplitSearchTermMixin, |
|
71 |
AutoModelSelect2Field): |
|
72 |
queryset = get_user_model().objects |
|
73 |
search_fields = [ |
|
74 |
'username__icontains', 'first_name__icontains', |
|
75 |
'last_name__icontains', 'email__icontains' |
|
76 |
] |
|
77 | ||
78 |
def get_results(self, request, term, page, context): |
|
79 |
return (NO_ERR_RESP, False, utils.search_user(term)) |
|
80 | ||
81 | ||
82 |
class ChooseUsersField(SecurityCheckMixin, SplitSearchTermMixin, |
|
83 |
AutoModelSelect2MultipleField): |
|
84 |
queryset = get_user_model().objects |
|
85 |
search_fields = [ |
|
86 |
'username__icontains', 'first_name__icontains', |
|
87 |
'last_name__icontains', 'email__icontains' |
|
88 |
] |
|
89 | ||
90 |
def get_results(self, request, term, page, context): |
|
91 |
return (NO_ERR_RESP, False, utils.search_user(term)) |
|
92 | ||
93 | ||
94 |
class GroupsField(SecurityCheckMixin, SplitSearchTermMixin, |
|
95 |
AutoModelSelect2MultipleField): |
|
96 |
queryset = Group.objects |
|
97 |
search_fields = [ |
|
98 |
'name__icontains', |
|
99 |
] |
|
100 | ||
101 | ||
102 |
class PermissionChoices(SecurityCheckMixin, SplitSearchTermMixin, |
|
103 |
AutoModelSelect2MultipleField): |
|
104 |
queryset = Permission.objects |
|
105 |
search_fields = [ |
|
106 |
'name__icontains', 'codename__icontains', |
|
107 |
'content_type__name__icontains' |
|
108 |
] |
|
109 | ||
110 |
def prepare_qs_params(self, request, search_term, search_fields): |
|
111 |
ors = [] |
|
112 |
ands = {} |
|
113 |
for term in search_term.split(): |
|
114 |
qs_params = super(PermissionChoices, self).prepare_qs_params( |
|
115 |
request, term, search_fields) |
|
116 |
ors.extend(qs_params['or']) |
|
117 |
ands.update(qs_params['and']) |
|
118 |
return {'or': ors, 'and': ands} |
|
119 | ||
120 |
def label_from_instance(self, instance): |
|
121 |
return instance.name |
|
122 | ||
123 | ||
124 |
class RoleLabelMixin(object): |
|
125 |
def label_from_instance(self, obj): |
|
126 |
label = unicode(obj) |
|
127 |
if obj.service: |
|
128 |
label = label + ' - ' + unicode(obj.service) |
|
129 |
return label |
|
130 | ||
131 | ||
132 |
class ChooseRoleField(RoleLabelMixin, SecurityCheckMixin, SplitSearchTermMixin, |
|
133 |
AutoModelSelect2Field): |
|
134 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
135 |
search_fields = [ |
|
136 |
'name__icontains', |
|
137 |
'service__name__icontains', |
|
138 |
] |
|
139 | ||
140 | ||
141 |
class ChooseRolesField(RoleLabelMixin, SecurityCheckMixin, SplitSearchTermMixin, |
|
142 |
AutoModelSelect2MultipleField): |
|
143 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
144 |
search_fields = [ |
|
145 |
'name__icontains', |
|
146 |
'service__name__icontains', |
|
147 |
] |
|
148 | ||
149 | ||
150 |
class ChooseRolesForChangeField(RoleLabelMixin, SecurityCheckMixin, SplitSearchTermMixin, |
|
151 |
AutoModelSelect2MultipleField): |
|
152 |
operations = ['change'] |
|
153 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
154 |
search_fields = [ |
|
155 |
'name__icontains', |
|
156 |
'service__name__icontains', |
|
157 |
] |
|
158 | ||
159 |
class ChooseOUField(SecurityCheckMixin, SplitSearchTermMixin, |
|
160 |
AutoModelSelect2Field): |
|
161 |
queryset = get_ou_model().objects |
|
162 |
search_fields = [ |
|
163 |
'name__icontains', |
|
164 |
] |
|
165 | ||
166 | ||
167 |
class ChooseServiceField(SecurityCheckMixin, SplitSearchTermMixin, |
|
168 |
AutoModelSelect2Field): |
|
169 |
queryset = Service.objects |
|
170 |
search_fields = [ |
|
171 |
'name__icontains', |
|
172 |
] |
|
173 | ||
174 | ||
175 |
class ChooseUserRoleField(RoleLabelMixin, SecurityCheckMixin, SplitSearchTermMixin, |
|
176 |
AutoModelSelect2Field): |
|
177 |
operations = ['change'] |
|
178 |
queryset = get_role_model().objects |
|
179 |
search_fields = [ |
|
180 |
'name__icontains', |
|
181 |
'service__name__icontains', |
|
182 |
] |
|
13 |
raise NotImplementedError |
|
14 |
assert kwargs['queryset'] is not None |
|
15 |
super(Select2Mixin, self).__init__(**kwargs) |
|
16 | ||
17 |
def __setattr__(self, key, value): |
|
18 |
if key == 'queryset': |
|
19 |
self.widget.queryset = value |
|
20 |
super(Select2Mixin, self).__setattr__(key, value) |
|
21 | ||
22 | ||
23 |
class Select2ModelChoiceField(Select2Mixin, forms.ModelChoiceField): |
|
24 |
pass |
|
25 | ||
26 | ||
27 |
class Select2ModelMultipleChoiceField(Select2Mixin, forms.ModelMultipleChoiceField): |
|
28 |
pass |
|
29 | ||
30 | ||
31 |
for key in dir(widgets): |
|
32 |
cls = getattr(widgets, key) |
|
33 |
if not isinstance(cls, type): |
|
34 |
continue |
|
35 |
if issubclass(cls, widgets.ModelSelect2MultipleWidget): |
|
36 |
cls_name = key.replace('Widget', 'Field') |
|
37 |
vars()[cls_name] = type(cls_name, (Select2ModelMultipleChoiceField,), { |
|
38 |
'widget': cls, |
|
39 |
}) |
|
40 |
elif issubclass(cls, widgets.ModelSelect2Widget): |
|
41 |
cls_name = key.replace('Widget', 'Field') |
|
42 |
vars()[cls_name] = type(cls_name, (Select2ModelChoiceField,), { |
|
43 |
'widget': cls, |
|
44 |
}) |
src/authentic2/manager/static/authentic2/manager/css/style.css | ||
---|---|---|
56 | 56 |
align-items: baseline; |
57 | 57 |
} |
58 | 58 | |
59 |
.manager-m2m-add-form .select2-container { |
|
60 |
flex-grow: 1; |
|
61 |
margin: 0 1em; |
|
62 |
} |
|
63 | ||
64 | 59 |
table.main th.name, table.main td.name, #user-table .link, #user-table .username, #user-table |
65 | 60 |
.email, #user-table .first_name, #user-table .last_name, #user-table .ou { |
66 | 61 |
text-align: left; |
... | ... | |
205 | 200 |
width: calc(100% - 28px); |
206 | 201 |
} |
207 | 202 | |
208 |
form p .select2-container { |
|
209 |
width: calc(100% - 10px); |
|
210 |
margin-left: 10px; |
|
211 |
} |
|
212 | ||
213 | 203 |
form input[type="checkbox"] { |
214 | 204 |
width: auto; |
215 | 205 |
} |
... | ... | |
226 | 216 |
margin-left: 50%; |
227 | 217 |
} |
228 | 218 | |
229 |
# Override jquery-ui default |
|
230 |
.ui-widget select { |
|
231 |
font-family: inherit; |
|
232 |
font-size: inherit; |
|
233 |
} |
|
234 | ||
235 |
div.ui-dialog form p select, form p select { |
|
236 |
width: calc(100% - 28px); |
|
237 |
} |
|
238 | 219 | |
239 | 220 |
#id_generate_password_p label, #id_reset_password_at_next_login_p label, |
240 | 221 |
#id_send_mail_p label, #id_is_superuser_p label { |
... | ... | |
259 | 240 |
width: 50%; |
260 | 241 |
} |
261 | 242 | |
262 |
.ui-widget-content { |
|
263 |
color: #3c3c33; |
|
264 |
} |
|
265 | ||
266 |
.ui-widget, .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { |
|
267 |
font-family: "Bitstream Vera Sans","Verdana",sans-serif; |
|
268 |
font-size: inherit; |
|
269 |
} |
|
270 | ||
271 | 243 |
.waiting { |
272 | 244 |
position: fixed; |
273 | 245 |
top: 0; |
... | ... | |
287 | 259 |
margin-right: 1ex; |
288 | 260 |
} |
289 | 261 |
.role-inheritance { margin: 1em 0px; } |
262 | ||
263 |
/* Select2 styling */ |
|
264 | ||
265 |
.select2-container { |
|
266 |
width: 100% !important; |
|
267 |
} |
src/authentic2/manager/templates/authentic2/manager/base.html | ||
---|---|---|
1 | 1 |
{% extends "gadjo/base.html" %} |
2 | 2 |
{% load i18n staticfiles %} |
3 |
{% load django_select2_tags %} |
|
4 | 3 |
{% load firstof from future %} |
5 | 4 | |
6 | 5 |
{% block page-title %}{% firstof site_title "Authentic2" %}{% endblock %} |
... | ... | |
19 | 18 |
<h2>{% block page_title %}{% endblock %}</h2> |
20 | 19 |
{% endblock %} |
21 | 20 | |
22 |
{% block css %} |
|
23 |
{{ block.super }} |
|
24 |
<link rel="stylesheet" type="text/css" media="all" href="{% static "authentic2/manager/css/style.css" %}"/> |
|
25 |
{% endblock %} |
|
26 | ||
27 | 21 |
{% block extrascripts %} |
28 | 22 |
{{ block.super }} |
29 |
{% if debug %} |
|
30 |
<script src="{% static "jquery/js/jquery.form.js" %}"></script> |
|
31 |
{% else %} |
|
32 |
<script src="{% static "jquery/js/jquery.form.min.js" %}"></script> |
|
33 |
{% endif %} |
|
34 |
<script type="text/javascript" src="{% static "admin/js/urlify.js" %}"></script> |
|
35 |
<script type="text/javascript" src="{% static "authentic2/js/purl.js" %}"></script> |
|
36 |
<script type="text/javascript" src="{% static "authentic2/manager/js/manager.js" %}"></script> |
|
37 |
{% import_django_select2_js %} |
|
38 |
{% import_django_select2_css %} |
|
39 |
<script type="text/javascript" src="{% url 'a2-manager-javascript-catalog' %}"></script> |
|
40 |
<script type="text/javascript" src="{% static "authentic2/manager/js/select2_locale.js" %}"></script> |
|
41 | 23 |
<script> |
42 | 24 |
window.csrf_token = '{{ csrf_token }}'; |
43 | 25 |
</script> |
src/authentic2/manager/templates/authentic2/manager/form.html | ||
---|---|---|
73 | 73 |
{% endif %} |
74 | 74 |
{% endblock %} |
75 | 75 |
</div> |
76 |
<script> |
|
77 |
$(function () { |
|
78 |
if ($.fn.djangoSelect2) { |
|
79 |
$('.django-select2').djangoSelect2(); |
|
80 |
} |
|
81 |
}) |
|
82 |
</script> |
|
76 | 83 |
{% endblock %} |
src/authentic2/manager/urls.py | ||
---|---|---|
92 | 92 |
url(r'^jsi18n/$', javascript_catalog, |
93 | 93 |
{'packages': ('authentic2.manager',)}, |
94 | 94 |
name='a2-manager-javascript-catalog'), |
95 |
url(r'^', include('django_select2.urls')),
|
|
95 |
url(r'^select2.json$', views.select2, name='django_select2-json'),
|
|
96 | 96 |
) |
src/authentic2/manager/views.py | ||
---|---|---|
2 | 2 | |
3 | 3 |
from django.core.exceptions import PermissionDenied |
4 | 4 |
from django.views.generic.base import ContextMixin |
5 |
from django.views.generic import TemplateView, FormView, UpdateView, \
|
|
6 |
CreateView, DeleteView, TemplateView |
|
5 |
from django.views.generic.edit import FormMixinBase
|
|
6 |
from django.views.generic import (FormView, UpdateView, CreateView, DeleteView, TemplateView) |
|
7 | 7 |
from django.views.generic.detail import SingleObjectMixin |
8 | 8 |
from django.http import HttpResponse, Http404 |
9 | 9 |
from django.utils.encoding import force_text |
10 | 10 |
from django.utils.translation import ugettext_lazy as _ |
11 | 11 |
from django.utils.timezone import now |
12 |
from django.core.urlresolvers import reverse |
|
12 |
from django.core.urlresolvers import reverse, reverse_lazy
|
|
13 | 13 |
from django.contrib.messages.views import SuccessMessageMixin |
14 |
from django.forms import MediaDefiningClass |
|
14 | 15 | |
15 | 16 |
from django_tables2 import SingleTableView, SingleTableMixin |
16 | 17 | |
18 |
from django_select2.views import AutoResponseView |
|
19 | ||
17 | 20 |
from django_rbac.utils import get_ou_model |
18 | 21 | |
19 | 22 |
from authentic2.forms import modelform_factory |
... | ... | |
23 | 26 |
from . import app_settings |
24 | 27 | |
25 | 28 | |
29 |
class MediaMixinBase(MediaDefiningClass, FormMixinBase): |
|
30 |
pass |
|
31 | ||
32 | ||
33 |
class MediaMixin(object): |
|
34 |
__metaclass__ = MediaMixinBase |
|
35 | ||
36 |
class Media: |
|
37 |
js = ( |
|
38 |
reverse_lazy('a2-manager-javascript-catalog'), |
|
39 |
'xstatic/jquery.js', |
|
40 |
'jquery/js/jquery.form.js', |
|
41 |
'admin/js/urlify.js', |
|
42 |
'authentic2/js/purl.js', |
|
43 |
'authentic2/manager/js/manager.js', |
|
44 |
) |
|
45 |
css = { |
|
46 |
'all': ( |
|
47 |
'authentic2/manager/css/style.css', |
|
48 |
) |
|
49 |
} |
|
50 | ||
51 |
def get_context_data(self, **kwargs): |
|
52 |
kwargs['media'] = self.media |
|
53 |
ctx = super(MediaMixin, self).get_context_data(**kwargs) |
|
54 |
if 'form' in ctx: |
|
55 |
ctx['media'] += ctx['form'].media |
|
56 |
return ctx |
|
57 | ||
58 | ||
26 | 59 |
class PermissionMixin(object): |
27 | 60 |
permissions = None |
28 | 61 | |
... | ... | |
266 | 299 |
return response |
267 | 300 | |
268 | 301 | |
269 |
class ModelNameMixin(object):
|
|
302 |
class ModelNameMixin(MediaMixin):
|
|
270 | 303 |
def get_model_name(self): |
271 | 304 |
return self.model._meta.verbose_name |
272 | 305 | |
... | ... | |
281 | 314 |
TableQuerysetMixin, SingleTableView): |
282 | 315 |
pass |
283 | 316 | |
284 |
class SubTableViewMixin(FormatsContextData, PermissionMixin, |
|
317 | ||
318 |
class SubTableViewMixin(FormatsContextData, ModelNameMixin, PermissionMixin, |
|
285 | 319 |
SearchFormMixin, FilterTableQuerysetByPermMixin, |
286 | 320 |
TableQuerysetMixin, SingleObjectMixin, |
287 | 321 |
SingleTableMixin, ContextMixin): |
288 | 322 |
pass |
289 | 323 | |
324 | ||
290 | 325 |
class SimpleSubTableView(SubTableViewMixin, TemplateView): |
291 | 326 |
pass |
292 | 327 | |
328 | ||
293 | 329 |
class BaseSubTableView(TitleMixin, SubTableViewMixin, FormView): |
294 | 330 |
success_url = '.' |
295 | 331 | |
... | ... | |
308 | 344 |
return '../../' |
309 | 345 | |
310 | 346 | |
311 |
class ModelFormView(object):
|
|
347 |
class ModelFormView(MediaMixin):
|
|
312 | 348 |
fields = None |
313 | 349 |
form_class = None |
314 | 350 | |
... | ... | |
349 | 385 |
return '..' |
350 | 386 | |
351 | 387 | |
352 |
class HomepageView(PermissionMixin, TemplateView): |
|
388 |
class HomepageView(PermissionMixin, MediaMixin, TemplateView):
|
|
353 | 389 |
template_name = 'authentic2/manager/homepage.html' |
354 | 390 |
permissions = ['a2_rbac.view_role', 'a2_rbac.view_organizationalunit', |
355 | 391 |
'auth.view_group', 'custom_user.view_user'] |
... | ... | |
406 | 442 |
if exclude_ou: |
407 | 443 |
kwargs['exclude'] = ['ou'] |
408 | 444 |
return super(HideOUColumnMixin, self).get_table(**kwargs) |
445 | ||
446 | ||
447 |
class Select2View(AutoResponseView): |
|
448 |
def get_widget_or_404(self): |
|
449 |
widget = super(Select2View, self).get_widget_or_404() |
|
450 |
widget.view = self |
|
451 |
if hasattr(widget, 'security_check'): |
|
452 |
if not widget.security_check(self.request, *self.args, **self.kwargs): |
|
453 |
raise PermissionDenied |
|
454 |
return widget |
|
455 | ||
456 |
select2 = Select2View.as_view() |
src/authentic2/manager/widgets.py | ||
---|---|---|
1 |
from django_select2.forms import ModelSelect2Widget, ModelSelect2MultipleWidget |
|
2 | ||
3 |
from django.contrib.auth import get_user_model |
|
4 | ||
5 |
from django_rbac.backends import DjangoRBACBackend |
|
6 |
from django_rbac.utils import get_role_model, get_ou_model |
|
7 | ||
8 |
from authentic2.models import Service |
|
9 | ||
10 |
from . import utils |
|
11 | ||
12 | ||
13 |
class SplitTermMixin(object): |
|
14 |
def filter_queryset(self, term, queryset=None): |
|
15 |
if queryset is not None: |
|
16 |
qs = queryset.none() |
|
17 |
else: |
|
18 |
qs = self.get_queryset().none() |
|
19 |
for term in term.split(): |
|
20 |
qs |= super(SplitTermMixin, self).filter_queryset(term, queryset=queryset) |
|
21 |
return qs |
|
22 | ||
23 | ||
24 |
class SecurityCheckMixin(SplitTermMixin): |
|
25 |
operations = ['change', 'add', 'view', 'delete'] |
|
26 | ||
27 |
@property |
|
28 |
def perms(self): |
|
29 |
model = self.queryset.model |
|
30 |
app_label = model._meta.app_label |
|
31 |
model_name = model._meta.model_name |
|
32 |
return ['%s.%s_%s' % (app_label, perm, model_name) |
|
33 |
for perm in self.operations] |
|
34 | ||
35 |
def security_check(self, request, *args, **kwargs): |
|
36 |
return request.user.is_authenticated() \ |
|
37 |
and request.user.has_perm_any(self.perms) |
|
38 | ||
39 |
def filter_queryset(self, term, queryset=None): |
|
40 |
'''Only search visible objects''' |
|
41 |
if not hasattr(self, 'view'): |
|
42 |
return [] |
|
43 |
request = self.view.request |
|
44 |
qs = super(SecurityCheckMixin, self).filter_queryset(term, queryset=queryset) |
|
45 |
rbac_backend = DjangoRBACBackend() |
|
46 |
return rbac_backend.filter_by_perm(request.user, self.perms, qs) |
|
47 | ||
48 | ||
49 |
class RoleLabelMixin(object): |
|
50 |
def label_from_instance(self, obj): |
|
51 |
label = unicode(obj) |
|
52 |
if obj.service: |
|
53 |
label = label + ' - ' + unicode(obj.service) |
|
54 |
return label |
|
55 | ||
56 | ||
57 |
class ChooseUserWidget(SecurityCheckMixin, ModelSelect2Widget): |
|
58 |
model = get_user_model() |
|
59 |
search_fields = [ |
|
60 |
'username__icontains', 'first_name__icontains', |
|
61 |
'last_name__icontains', 'email__icontains' |
|
62 |
] |
|
63 | ||
64 |
def label_from_instance(self, user): |
|
65 |
return utils.label_from_user(user) |
|
66 | ||
67 | ||
68 |
class ChooseUsersWidget(SecurityCheckMixin, ModelSelect2MultipleWidget): |
|
69 |
model = get_user_model() |
|
70 |
search_fields = [ |
|
71 |
'username__icontains', 'first_name__icontains', |
|
72 |
'last_name__icontains', 'email__icontains' |
|
73 |
] |
|
74 | ||
75 |
def label_from_instance(self, user): |
|
76 |
return utils.label_from_user(user) |
|
77 | ||
78 | ||
79 |
class ChooseRoleWidget(RoleLabelMixin, SecurityCheckMixin, ModelSelect2Widget): |
|
80 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
81 |
search_fields = [ |
|
82 |
'name__icontains', |
|
83 |
'service__name__icontains', |
|
84 |
] |
|
85 | ||
86 | ||
87 |
class ChooseRolesWidget(RoleLabelMixin, SecurityCheckMixin, ModelSelect2MultipleWidget): |
|
88 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
89 |
search_fields = [ |
|
90 |
'name__icontains', |
|
91 |
'service__name__icontains', |
|
92 |
] |
|
93 | ||
94 | ||
95 |
class ChooseRolesForChangeWidget(RoleLabelMixin, SecurityCheckMixin, ModelSelect2MultipleWidget): |
|
96 |
operations = ['change'] |
|
97 |
queryset = get_role_model().objects.filter(admin_scope_ct__isnull=True) |
|
98 |
search_fields = [ |
|
99 |
'name__icontains', |
|
100 |
'service__name__icontains', |
|
101 |
] |
|
102 | ||
103 | ||
104 |
class ChooseOUWidget(SecurityCheckMixin, ModelSelect2Widget): |
|
105 |
model = get_ou_model() |
|
106 |
search_fields = [ |
|
107 |
'name__icontains', |
|
108 |
] |
|
109 | ||
110 | ||
111 |
class ChooseServiceWidget(SecurityCheckMixin, ModelSelect2Widget): |
|
112 |
model = Service |
|
113 |
search_fields = [ |
|
114 |
'name__icontains', |
|
115 |
] |
|
116 | ||
117 | ||
118 |
class ChooseUserRoleWidget(RoleLabelMixin, SecurityCheckMixin, ModelSelect2Widget): |
|
119 |
operations = ['change'] |
|
120 |
model = get_role_model() |
|
121 |
search_fields = [ |
|
122 |
'name__icontains', |
|
123 |
'service__name__icontains', |
|
124 |
] |
src/authentic2/settings.py | ||
---|---|---|
121 | 121 |
'rest_framework', |
122 | 122 |
'xstatic.pkg.jquery', |
123 | 123 |
'xstatic.pkg.jquery_ui', |
124 |
'xstatic.pkg.select2', |
|
124 | 125 |
) |
125 | 126 | |
126 | 127 |
INSTALLED_APPS = tuple(plugins.register_plugins_installed_apps(INSTALLED_APPS)) |
127 |
- |