Commit 00a31980 by Bach Dániel

dashboard: add autocomplete for AclUpdateView

parent 6f5d8cc0
...@@ -260,6 +260,7 @@ THIRD_PARTY_APPS = ( ...@@ -260,6 +260,7 @@ THIRD_PARTY_APPS = (
'taggit', 'taggit',
'statici18n', 'statici18n',
'django_sshkey', 'django_sshkey',
'autocomplete_light',
) )
# Apps specific for this project go here. # Apps specific for this project go here.
......
import autocomplete_light
from django.utils.translation import ugettext as _
from .views import AclUpdateView
class AclUserAutocomplete(autocomplete_light.AutocompleteGenericBase):
search_fields = (
('^first_name', 'last_name', 'username', '^email', 'profile__org_id'),
('^name', 'groupprofile__org_id'),
)
autocomplete_js_attributes = {'placeholder': _("Name of group or user")}
def choices_for_request(self):
user = self.request.user
self.choices = (AclUpdateView.get_allowed_users(user),
AclUpdateView.get_allowed_groups(user))
return super(AclUserAutocomplete, self).choices_for_request()
autocomplete_light.register(AclUserAutocomplete)
...@@ -27,6 +27,7 @@ from django.contrib.auth.models import User, Group ...@@ -27,6 +27,7 @@ from django.contrib.auth.models import User, Group
from django.core.validators import URLValidator from django.core.validators import URLValidator
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
import autocomplete_light
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import ( from crispy_forms.layout import (
Layout, Div, BaseInput, Field, HTML, Submit, Fieldset, TEMPLATE_PACK, Layout, Div, BaseInput, Field, HTML, Submit, Fieldset, TEMPLATE_PACK,
...@@ -1185,6 +1186,11 @@ class UserCreationForm(OrgUserCreationForm): ...@@ -1185,6 +1186,11 @@ class UserCreationForm(OrgUserCreationForm):
return user return user
class AclUserAddForm(forms.Form):
name = forms.CharField(widget=autocomplete_light.TextWidget(
'AclUserAutocomplete', attrs={'class': 'form-control'}))
class UserKeyForm(forms.ModelForm): class UserKeyForm(forms.ModelForm):
name = forms.CharField(required=True, label=_('Name')) name = forms.CharField(required=True, label=_('Name'))
key = forms.CharField( key = forms.CharField(
......
...@@ -142,6 +142,11 @@ class Profile(Model): ...@@ -142,6 +142,11 @@ class Profile(Model):
def __unicode__(self): def __unicode__(self):
return self.get_display_name() return self.get_display_name()
class Meta:
permissions = (
('use_autocomplete', _('Can use autocomplete.')),
)
class FutureMember(Model): class FutureMember(Model):
org_id = CharField(max_length=64, help_text=_( org_id = CharField(max_length=64, help_text=_(
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="{{ STATIC_URL }}jsi18n/{{ LANGUAGE_CODE }}/djangojs.js"></script> <script src="{{ STATIC_URL }}jsi18n/{{ LANGUAGE_CODE }}/djangojs.js"></script>
{% include 'autocomplete_light/static.html' %}
{% block extra_script %} {% block extra_script %}
{% endblock %} {% endblock %}
......
...@@ -88,11 +88,12 @@ ...@@ -88,11 +88,12 @@
</tr> </tr>
{% endfor %} {% endfor %}
<tr><td><i class="fa fa-plus"></i></td> <tr><td><i class="fa fa-plus"></i></td>
<td><input type="text" class="form-control" name="perm-new-name" <td>{{aclform.name }}</td>
placeholder="{% trans "Name of group or user" %}"></td> <td><select class="form-control" name="level">
<td><select class="form-control" name="perm-new"> {% for id, name in acl.levels %}
{% for id, name in acl.allowed_levels %} {% if id in acl.allowed_levels %}
<option value="{{id}}">{{name}}</option> <option value="{{id}}">{{name}}</option>
{% endif %}
{% endfor %} {% endfor %}
</select></td><td></td> </select></td><td></td>
</tr> </tr>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
from __future__ import absolute_import from __future__ import absolute_import
from django.conf.urls import patterns, url, include from django.conf.urls import patterns, url, include
import autocomplete_light
from vm.models import Instance from vm.models import Instance
from .views import ( from .views import (
AclUpdateView, FavouriteView, GroupAclUpdateView, GroupDelete, AclUpdateView, FavouriteView, GroupAclUpdateView, GroupDelete,
...@@ -43,7 +44,10 @@ from .views import ( ...@@ -43,7 +44,10 @@ from .views import (
LeaseAclUpdateView, LeaseAclUpdateView,
) )
autocomplete_light.autodiscover()
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^$', IndexView.as_view(), name="dashboard.index"), url(r'^$', IndexView.as_view(), name="dashboard.index"),
url(r'^lease/(?P<pk>\d+)/$', LeaseDetail.as_view(), url(r'^lease/(?P<pk>\d+)/$', LeaseDetail.as_view(),
...@@ -181,4 +185,5 @@ urlpatterns = patterns( ...@@ -181,4 +185,5 @@ urlpatterns = patterns(
url(r'^sshkey/create/$', url(r'^sshkey/create/$',
UserKeyCreate.as_view(), UserKeyCreate.as_view(),
name="dashboard.views.userkey-create"), name="dashboard.views.userkey-create"),
url(r'^autocomplete/', include('autocomplete_light.urls')),
) )
...@@ -61,7 +61,7 @@ from .forms import ( ...@@ -61,7 +61,7 @@ from .forms import (
UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm, UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm,
VmSaveForm, UserKeyForm, VmRenewForm, VmSaveForm, UserKeyForm, VmRenewForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm, CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
TraitsForm, RawDataForm, GroupPermissionForm TraitsForm, RawDataForm, GroupPermissionForm, AclUserAddForm
) )
from .tables import ( from .tables import (
...@@ -1068,8 +1068,8 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -1068,8 +1068,8 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
if cls.has_next_level(user, obj, l[0])) if cls.has_next_level(user, obj, l[0]))
is_owner = 'owner' in allowed_levels is_owner = 'owner' in allowed_levels
allowed_users = cls.get_allowed_users(user, is_owner) allowed_users = cls.get_allowed_users(user)
allowed_groups = cls.get_allowed_groups(user, is_owner) allowed_groups = cls.get_allowed_groups(user)
user_levels = list( user_levels = list(
{'user': u, 'level': l} for u, l in obj.get_users_with_level() {'user': u, 'level': l} for u, l in obj.get_users_with_level()
...@@ -1100,30 +1100,28 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -1100,30 +1100,28 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
return instance.has_level(user, next_level) return instance.has_level(user, next_level)
@classmethod @classmethod
def get_allowed_groups(cls, user, is_owner): def get_allowed_groups(cls, user):
if is_owner: if user.has_perm('dashboard.use_autocomplete'):
return Group.objects.all() return Group.objects.all()
else: else:
profiles = GroupProfile.get_objects_with_level('owner', user) profiles = GroupProfile.get_objects_with_level('owner', user)
return Group.objects.filter(groupprofile__in=profiles).distinct() return Group.objects.filter(groupprofile__in=profiles).distinct()
@classmethod @classmethod
def get_allowed_users(cls, user, is_owner): def get_allowed_users(cls, user):
if is_owner: if user.has_perm('dashboard.use_autocomplete'):
return User.objects.all() return User.objects.all()
else: else:
groups = cls.get_allowed_groups(user, is_owner) groups = cls.get_allowed_groups(user)
return User.objects.filter( return User.objects.filter(
Q(groups__in=groups) | Q(pk=user.pk)).distinct() Q(groups__in=groups) | Q(pk=user.pk)).distinct()
def check_auth(self, whom, old_level, new_level): def check_auth(self, whom, old_level, new_level):
if isinstance(whom, Group): if isinstance(whom, Group):
if whom not in AclUpdateView.get_allowed_groups(self.request.user, if whom not in AclUpdateView.get_allowed_groups(self.request.user):
self.is_owner):
return False return False
elif isinstance(whom, User): elif isinstance(whom, User):
if whom not in AclUpdateView.get_allowed_users(self.request.user, if whom not in AclUpdateView.get_allowed_users(self.request.user):
self.is_owner):
return False return False
return ( return (
AclUpdateView.has_next_level(self.request.user, AclUpdateView.has_next_level(self.request.user,
...@@ -1168,9 +1166,9 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -1168,9 +1166,9 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
self.set_level(entity, value) self.set_level(entity, value)
def add_levels(self): def add_levels(self):
name = self.request.POST.get('perm-new-name', None) name = self.request.POST.get('name', None)
value = self.request.POST.get('perm-new', None) level = self.request.POST.get('level', None)
if not name or not value: if not name or not level:
return return
try: try:
entity = search_user(name) entity = search_user(name)
...@@ -1182,7 +1180,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -1182,7 +1180,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
messages.warning( messages.warning(
self.request, _('User or group "%s" not found.') % name) self.request, _('User or group "%s" not found.') % name)
return return
self.set_level(entity, value) self.set_level(entity, level)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.instance = self.get_object() self.instance = self.get_object()
...@@ -1352,6 +1350,7 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView): ...@@ -1352,6 +1350,7 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
obj, self.request.user, 'dashboard.views.template-acl') obj, self.request.user, 'dashboard.views.template-acl')
context['disks'] = obj.disks.all() context['disks'] = obj.disks.all()
context['is_owner'] = obj.has_level(self.request.user, 'owner') context['is_owner'] = obj.has_level(self.request.user, 'owner')
context['aclform'] = AclUserAddForm()
return context return context
def get_success_url(self): def get_success_url(self):
......
...@@ -4,6 +4,7 @@ billiard==3.3.0.17 ...@@ -4,6 +4,7 @@ billiard==3.3.0.17
bpython==0.12 bpython==0.12
celery==3.1.11 celery==3.1.11
Django==1.6.3 Django==1.6.3
django-autocomplete-light==1.4.14
django-braces==1.4.0 django-braces==1.4.0
django-celery==3.1.10 django-celery==3.1.10
django-crispy-forms==1.4.0 django-crispy-forms==1.4.0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment