diff --git a/circle/dashboard/static/dashboard/template-list.js b/circle/dashboard/static/dashboard/template-list.js index e0d82b5..a3e45ff 100644 --- a/circle/dashboard/static/dashboard/template-list.js +++ b/circle/dashboard/static/dashboard/template-list.js @@ -2,7 +2,7 @@ $(function() { /* for template removes buttons */ $('.template-delete').click(function() { var template_pk = $(this).data('template-pk'); - addModalConfirmation(deleteTemplate, + addModalConfirmationOrDisplayMessage(deleteTemplate, { 'url': '/dashboard/template/delete/' + template_pk + '/', 'data': [], 'template_pk': template_pk, @@ -13,7 +13,7 @@ $(function() { /* for lease removes buttons */ $('.lease-delete').click(function() { var lease_pk = $(this).data('lease-pk'); - addModalConfirmation(deleteLease, + addModalConfirmationOrDisplayMessage(deleteLease, { 'url': '/dashboard/lease/delete/' + lease_pk + '/', 'data': [], 'lease_pk': lease_pk, @@ -81,3 +81,29 @@ function deleteLease(data) { } }); } + +function addModalConfirmationOrDisplayMessage(func, data) { + $.ajax({ + type: 'GET', + url: data['url'], + data: jQuery.param(data['data']), + success: function(result) { + $('body').append(result); + $('#confirmation-modal').modal('show'); + $('#confirmation-modal').on('hidden.bs.modal', function() { + $('#confirmation-modal').remove(); + }); + $('#confirmation-modal-button').click(function() { + func(data); + $('#confirmation-modal').modal('hide'); + }); + }, + error: function(xhr, textStatus, error) { + if(xhr.status === 403) { + addMessage(gettext("Only the owners can delete the selected object."), "warning"); + } else { + addMessage(gettext("An error occurred. (") + xhr.status + ")", 'danger') + } + } + }); +} diff --git a/circle/dashboard/templates/dashboard/template-edit.html b/circle/dashboard/templates/dashboard/template-edit.html index d6bc6b5..e0c8972 100644 --- a/circle/dashboard/templates/dashboard/template-edit.html +++ b/circle/dashboard/templates/dashboard/template-edit.html @@ -11,7 +11,9 @@ <div class="col-md-7"> <div class="panel panel-default"> <div class="panel-heading"> - <a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}">{% trans "Back" %}</a> + <a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.template-list" %}"> + {% trans "Back" %} + </a> <h3 class="no-margin"><i class="fa fa-puzzle-piece"></i> {% trans "Edit template" %}</h3> </div> <div class="panel-body"> @@ -65,6 +67,18 @@ </div> <div class="col-md-5"> + {% if is_owner %} + <div class="panel panel-default"> + <div class="panel-heading"> + <a href="{% url "dashboard.views.template-delete" pk=object.pk %}" + class="btn btn-xs btn-danger pull-right"> + {% trans "Delete" %} + </a> + <h4 class="no-margin"><i class="fa fa-times"></i> {% trans "Delete template" %}</h4> + </div> + </div> + {% endif %} + <div class="panel panel-default"> <div class="panel-heading"> <h4 class="no-margin"><i class="fa fa-group"></i> {% trans "Manage access" %}</h4> diff --git a/circle/dashboard/tests/test_views.py b/circle/dashboard/tests/test_views.py index 8268da3..7990767 100644 --- a/circle/dashboard/tests/test_views.py +++ b/circle/dashboard/tests/test_views.py @@ -299,7 +299,7 @@ class VmDetailTest(LoginMixin, TestCase): leases = Lease.objects.count() response = c.post("/dashboard/lease/delete/1/") # redirect to the login page - self.assertEqual(response.status_code, 302) + self.assertEqual(response.status_code, 403) self.assertEqual(leases, Lease.objects.count()) def test_notification_read(self): diff --git a/circle/dashboard/views/template.py b/circle/dashboard/views/template.py index d5fd13b..a7454dc 100644 --- a/circle/dashboard/views/template.py +++ b/circle/dashboard/views/template.py @@ -32,7 +32,7 @@ from django.views.generic import ( ) from braces.views import ( - LoginRequiredMixin, PermissionRequiredMixin, SuperuserRequiredMixin, + LoginRequiredMixin, PermissionRequiredMixin, ) from django_tables2 import SingleTableView @@ -240,6 +240,16 @@ class TemplateDelete(LoginRequiredMixin, DeleteView): else: return ['dashboard/confirm/base-delete.html'] + def get(self, request, *args, **kwargs): + if not self.get_object().has_level(request.user, "owner"): + message = _("Only the owners can delete the selected template.") + if request.is_ajax(): + raise PermissionDenied() + else: + messages.warning(request, message) + return redirect(self.get_success_url()) + return super(TemplateDelete, self).get(request, *args, **kwargs) + def delete(self, request, *args, **kwargs): object = self.get_object() if not object.has_level(request.user, 'owner'): @@ -382,13 +392,17 @@ class LeaseCreate(LoginRequiredMixin, PermissionRequiredMixin, def get_success_url(self): return reverse_lazy("dashboard.views.template-list") + def form_valid(self, form): + retval = super(LeaseCreate, self).form_valid(form) + self.object.set_level(self.request.user, "owner") + return retval + class LeaseAclUpdateView(AclUpdateView): model = Lease -class LeaseDetail(LoginRequiredMixin, SuperuserRequiredMixin, - SuccessMessageMixin, UpdateView): +class LeaseDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView): model = Lease form_class = LeaseForm template_name = "dashboard/lease-edit.html" @@ -404,8 +418,21 @@ class LeaseDetail(LoginRequiredMixin, SuperuserRequiredMixin, def get_success_url(self): return reverse_lazy("dashboard.views.lease-detail", kwargs=self.kwargs) + def get(self, request, *args, **kwargs): + if not self.get_object().has_level(request.user, "owner"): + message = _("Only the owners can modify the selected lease.") + messages.warning(request, message) + return redirect(reverse_lazy("dashboard.views.template-list")) + return super(LeaseDetail, self).get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + if not self.get_object().has_level(request.user, "owner"): + raise PermissionDenied() + + return super(LeaseDetail, self).post(request, *args, **kwargs) -class LeaseDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): + +class LeaseDelete(LoginRequiredMixin, DeleteView): model = Lease def get_success_url(self): @@ -431,10 +458,22 @@ class LeaseDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): c['disable_submit'] = True return c + def get(self, request, *args, **kwargs): + if not self.get_object().has_level(request.user, "owner"): + message = _("Only the owners can delete the selected lease.") + if request.is_ajax(): + raise PermissionDenied() + else: + messages.warning(request, message) + return redirect(self.get_success_url()) + return super(LeaseDelete, self).get(request, *args, **kwargs) + def delete(self, request, *args, **kwargs): object = self.get_object() - if (object.instancetemplate_set.count() > 0): + if not object.has_level(request.user, "owner"): + raise PermissionDenied() + if object.instancetemplate_set.count() > 0: raise SuspiciousOperation() object.delete()