Commit 387eb4e8 by Bach Dániel

Merge branch 'feature-node-permissions' into 'master'

Feature node permissions

Allow users with view_statistics to check the graphs and informations of the nodes.

See merge request !259
parents d0f4347b 76d043aa
......@@ -74,9 +74,11 @@
{% trans "list" %}
{% endif %}
</a>
{% if request.user.is_superuser %}
<a class="btn btn-success btn-xs node-create" href="{% url "dashboard.views.node-create" %}">
<i class="fa fa-plus-circle"></i> {% trans "new" %}
</a>
{% endif %}
</div>
</div>
</div>
......
......@@ -35,7 +35,7 @@
</div>
{% endif %}
{% if user.is_superuser %}
{% if perms.vm.view_statistics %}
<div class="col-lg-4 col-sm-6">
{% include "dashboard/index-nodes.html" %}
</div>
......
......@@ -6,14 +6,16 @@
{% block content %}
<div class="body-content">
<div class="page-header">
{% if request.user.is_superuser %}
<div class="pull-right" id="ops">
{% include "dashboard/vm-detail/_operations.html" %}
</div>
<div class="pull-right" style="padding-top: 15px;">
<a title="{% trans "Rename" %}" href="#" class="btn btn-default btn-xs node-details-rename-button"><i class="fa fa-pencil"></i></a>
<a title="{% trans "Delete" %}" data-node-pk="{{ node.pk }}" class="btn btn-default btn-xs real-link node-delete" href="{% url "dashboard.views.delete-node" pk=node.pk %}"><i class="fa fa-trash-o"></i></a>
<div class="pull-right" style="padding-top: 15px;">
<a title="{% trans "Rename" %}" href="#" class="btn btn-default btn-xs node-details-rename-button"><i class="fa fa-pencil"></i></a>
<a title="{% trans "Delete" %}" data-node-pk="{{ node.pk }}" class="btn btn-default btn-xs real-link node-delete" href="{% url "dashboard.views.delete-node" pk=node.pk %}"><i class="fa fa-trash-o"></i></a>
</div>
<h1>
{% endif %}
<h1>
<div id="node-details-rename">
<form action="" method="POST" id="node-details-rename-form">
{% csrf_token %}
......@@ -69,26 +71,26 @@
{% trans "Resources" %}
</a>
</li>
<li>
<li>
<a href="{% url "dashboard.views.vm-list" %}?s=node:{{ node.name }}"
target="blank" class="text-center">
<i class="fa fa-desktop fa-2x"></i><br>
{% trans "Virtual Machines" %}
</a>
</li>
<li>
<li>
<a href="#activity" data-toggle="pill" class="text-center">
<i class="fa fa-clock-o fa-2x"></i><br>
{% trans "Activity" %}
</a>
</li>
</ul>
</ul>
<div id="panel-body" class="tab-content panel-body">
<div class="tab-pane active" id="home">{% include "dashboard/node-detail/home.html" %}</div>
<div class="tab-pane" id="resources">{% include "dashboard/node-detail/resources.html" %}</div>
<div class="tab-pane" id="resources">{% include "dashboard/node-detail/resources.html" %}</div>
<div class="tab-pane" id="activity">{% include "dashboard/node-detail/activity.html" %}</div>
</div>
</div>
</div>
</div>
</div>
......
......@@ -16,16 +16,19 @@
{% endif %}
</div>
{% load crispy_forms_tags %}
<style>
.row {
margin-bottom: 15px;
}
</style>
<form action="{% url "dashboard.views.node-addtrait" node.pk %}" method="POST">
{% csrf_token %}
{% crispy trait_form %}
</form>
{% if request.user.is_superuser %}
<form action="{% url "dashboard.views.node-addtrait" node.pk %}" method="POST">
{% csrf_token %}
{% crispy trait_form %}
</form>
{% endif %}
</div><!-- id:node-details-traits -->
</div>
<div class="col-md-8">
......
......@@ -18,10 +18,12 @@
<dt>{% trans "Host name" %}:</dt>
<dd>
{{ node.host.hostname }}
{% if request.user.is_superuser %}
<a href="{{ node.host.get_absolute_url }}" class="btn btn-default btn-xs">
<i class="fa fa-pencil"></i>
{% trans "Edit host" %}
</a>
{% endif %}
</dd>
</dl>
......
......@@ -637,7 +637,7 @@ class NodeDetailTest(LoginMixin, TestCase):
c = Client()
self.login(c, 'user1')
response = c.get('/dashboard/node/25555/')
self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 403)
def test_anon_node_page(self):
c = Client()
......@@ -667,7 +667,7 @@ class NodeDetailTest(LoginMixin, TestCase):
node = Node.objects.get(pk=1)
old_name = node.name
response = c.post("/dashboard/node/1/", {'new_name': 'test1235'})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 403)
self.assertEqual(Node.objects.get(pk=1).name, old_name)
def test_permitted_set_name(self):
......@@ -721,7 +721,7 @@ class NodeDetailTest(LoginMixin, TestCase):
c = Client()
self.login(c, "user2")
response = c.post("/dashboard/node/1/", {'to_remove': traitid})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.status_code, 403)
self.assertEqual(Node.objects.get(pk=1).traits.count(), trait_count)
def test_permitted_remove_trait(self):
......
......@@ -26,7 +26,7 @@ from django.http import HttpResponse, Http404
from django.utils.translation import ugettext_lazy as _
from django.views.generic import View
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from braces.views import LoginRequiredMixin
from vm.models import Instance, Node
......@@ -142,22 +142,28 @@ class VmGraphView(GraphViewBase):
base = VmMetric
class NodeGraphView(SuperuserRequiredMixin, GraphViewBase):
class NodeGraphView(GraphViewBase):
model = Node
base = NodeMetric
def get_object(self, request, pk):
if not self.request.user.has_perm('vm.view_statistics'):
raise PermissionDenied()
return self.model.objects.get(id=pk)
class NodeListGraphView(SuperuserRequiredMixin, GraphViewBase):
class NodeListGraphView(GraphViewBase):
model = Node
base = Metric
def get_object(self, request, pk):
if not self.request.user.has_perm('vm.view_statistics'):
raise PermissionDenied()
return Node.objects.filter(enabled=True)
def get(self, request, metric, time, *args, **kwargs):
if not self.request.user.has_perm('vm.view_statistics'):
raise PermissionDenied()
return super(NodeListGraphView, self).get(request, None, metric, time)
......
......@@ -62,7 +62,7 @@ class IndexView(LoginRequiredMixin, TemplateView):
})
# nodes
if user.is_superuser:
if user.has_perm('vm.view_statistics'):
nodes = Node.objects.all()
context.update({
'nodes': nodes[:5],
......
......@@ -75,13 +75,18 @@ node_ops = OrderedDict([
])
class NodeDetailView(LoginRequiredMixin, SuperuserRequiredMixin,
class NodeDetailView(LoginRequiredMixin,
GraphMixin, DetailView):
template_name = "dashboard/node-detail.html"
model = Node
form = None
form_class = TraitForm
def get(self, *args, **kwargs):
if not self.request.user.has_perm('vm.view_statistics'):
raise PermissionDenied()
return super(NodeDetailView, self).get(*args, **kwargs)
def get_context_data(self, form=None, **kwargs):
if form is None:
form = self.form_class()
......@@ -98,6 +103,8 @@ class NodeDetailView(LoginRequiredMixin, SuperuserRequiredMixin,
return context
def post(self, request, *args, **kwargs):
if not request.user.is_superuser:
raise PermissionDenied()
if request.POST.get('new_name'):
return self.__set_name(request)
if request.POST.get('to_remove'):
......@@ -145,13 +152,14 @@ class NodeDetailView(LoginRequiredMixin, SuperuserRequiredMixin,
return redirect(self.object.get_absolute_url())
class NodeList(LoginRequiredMixin, SuperuserRequiredMixin,
GraphMixin, SingleTableView):
class NodeList(LoginRequiredMixin, GraphMixin, SingleTableView):
template_name = "dashboard/node-list.html"
table_class = NodeListTable
table_pagination = False
def get(self, *args, **kwargs):
if not self.request.user.has_perm('vm.view_statistics'):
raise PermissionDenied()
if self.request.is_ajax():
nodes = Node.objects.all()
nodes = [{
......
......@@ -88,7 +88,9 @@ class Node(OperatedMixin, TimeStampedModel):
class Meta:
app_label = 'vm'
db_table = 'vm_node'
permissions = ()
permissions = (
('view_statistics', _('Can view Node box and statistics.')),
)
ordering = ('-enabled', 'normalized_name')
def __unicode__(self):
......
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